#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys
from datetime import datetime
from decimal import Decimal
from itertools import chain

import numpy as np
import pandas as pd
from django.db.models import Q
from hmmlearn.hmm import GaussianHMM
from matplotlib import pyplot as plt
from scipy.stats import boxcox
from sklearn import preprocessing

from algorithm.config.hmm_config import HmmConfig
from web.constants.datetime_format import DatetimeFormat
from web.constants.direction import Direction
from web.manager.log_manager import LogManager
from web.models import CommodityFutureDateData
from web.models.model_hmm import ModelHmm
from web.service.base_service import BaseService
from web.util.datetime_util import DatetimeUtil
from web.util.math_util import MathUtil
from web.util.picture_util import PictureUtil

Logger = LogManager.get_logger(__name__)


class ModelHmmService(BaseService):
    """
    ModelCommodityFutureDateDataClosePriceMA5DeadCross的service类
    """

    def training_all_commodity_future_with_few_eigenvalue(self):
        """
        hmm算法，测试所有期货（主力连续）数据：生成直方图、在训练数据集中学习，在测试数据集中测试。（使用少量特征值）
        """

        # 查询所有期货信息
        commodity_future_info_list: list = (self.commodity_future_info_dao.find_for_hmm())
        for commodity_future_info in commodity_future_info_list:
            Logger.info("开始测试期货[" + commodity_future_info.code + commodity_future_info.name + "]")

            try:
                # 查询某个期货的全部记录
                filter_dict: dict = {"code": commodity_future_info.code}
                order_by_list: list = ['transaction_date']
                commodity_future_date_data_list: CommodityFutureDateData = (
                    self.commodity_future_date_data_dao
                    .find_list(filter_dict, dict(), order_by_list))

                # 判断某个期货的交易记录数是否满足要求
                if len(commodity_future_date_data_list) < HmmConfig.Training_Data_Number:
                    Logger.warning("期货[" + commodity_future_info.code + "]的记录数量为" + str(len(
                        commodity_future_info_list)) + "，不足" + str(HmmConfig.Training_Data_Number) + "个，因此不做测试")
                    continue

                # 当前收益率，初始化为100%
                testing_current_profit: float = 100.00
                # 是否持有多单
                testing_holding_long: bool = False
                # 是否持有空单
                testing_holding_short: bool = False
                # 开多仓价格
                testing_open_buying_price: float
                # 开多仓日期
                testing_open_buying_date: datetime
                # 平多仓价格
                testing_close_buying_price: float
                # 平多仓日期
                testing_close_buying_date: datetime
                # 开空仓价格
                testing_open_sell_price: float
                # 开空仓日期
                testing_open_sell_date: datetime
                # 平空仓价格
                testing_close_sell_price: float
                # 平空仓日期
                testing_close_selling_price: datetime
                # 记录所有状态收益率的二维数组
                testing_profit_ndarray = np.zeros(
                    (HmmConfig.Status_Number, len(commodity_future_date_data_list) - HmmConfig.Training_Data_Number))
                # 初始化记录所有状态收益率的二维数组
                testing_profit_ndarray[:, 0].fill(testing_current_profit)
                # 测试的索引
                testing_index: int = 0
                # 测试时，上一个交易日的收益率
                testing_last_profit_and_loss_rate: float = 100.00

                for training_index, commodity_future_date_data in enumerate(commodity_future_date_data_list):
                    training_index = training_index + 1
                    if training_index < HmmConfig.Training_Data_Number + HmmConfig.Logarithm_Date_Number:
                        continue

                    # 训练样本开始时间
                    training_begin_date: datetime.date = commodity_future_date_data_list[
                        training_index - HmmConfig.Training_Data_Number].transaction_date
                    # 训练样本结束时间
                    training_end_date: datetime.date = commodity_future_date_data.transaction_date
                    Logger.info("训练样本的开始时间是[" + DatetimeUtil.datetime_to_str(training_begin_date,
                                                                                       DatetimeFormat.Date_Format_With_Line) +
                                "]，结束时间是[" + DatetimeUtil.datetime_to_str(training_end_date,
                                                                               DatetimeFormat.Date_Format_With_Line) + "]")

                    # 获取总体样本数据
                    (training_one_day_log_turnover_difference_list, training_five_day_log_turnover_difference_list,
                     training_one_day_log_close_price_difference_list, training_five_day_log_close_price_difference_list,
                     training_five_day_log_highest_price_lowest_price_difference_list, training_transaction_date_list,
                     training_close_price_list, training_total_number) = (self.commodity_future_date_data_dao.prepare_for_hmm_with_few_eigenvalue(
                        commodity_future_info.code, training_begin_date, training_end_date))

                    # 划分训练数据和测试数据
                    # training_data_number = int(total_number * (1 - HmmConfig.Training_Data_Number))
                    # training_one_day_log_turnover_difference_list = one_day_log_turnover_difference_list[
                    #                                                 :training_data_number]
                    # testing_one_day_log_turnover_difference_list = one_day_log_turnover_difference_list[
                    #                                                training_data_number:]
                    # training_five_day_log_turnover_difference_list = five_day_log_turnover_difference_list[
                    #                                                  :training_data_number]
                    # testing_five_day_log_turnover_difference_list = five_day_log_turnover_difference_list[
                    #                                                 training_data_number:]
                    # training_one_day_log_close_price_difference_list = one_day_log_close_price_difference_list[
                    #                                                    :training_data_number]
                    # testing_one_day_log_close_price_difference_list = one_day_log_close_price_difference_list[
                    #                                                   training_data_number:]
                    # training_five_day_log_close_price_difference_list = five_day_log_close_price_difference_list[
                    #                                                     :training_data_number]
                    # testing_five_day_log_close_price_difference_list = five_day_log_close_price_difference_list[
                    #                                                    training_data_number:]
                    # training_five_day_log_highest_price_lowest_price_difference_list = five_day_log_highest_price_lowest_price_difference_list[
                    #                                                                    :training_data_number]
                    # testing_five_day_log_highest_price_lowest_price_difference_list = five_day_log_highest_price_lowest_price_difference_list[
                    #                                                                   training_data_number:]
                    # training_transaction_date_list = transaction_date_list[:training_data_number]
                    # testing_transaction_date_list = transaction_date_list[training_data_number:]
                    # training_close_price_list = close_price_list[:training_data_number]
                    # testing_close_price_list = close_price_list[training_data_number:]

                    # 生成直方图
                    if HmmConfig.Save_Histogram_Picture:
                        PictureUtil.create_histogram_picture('一日对数成交量差', HmmConfig.Save_Hmm_Histogram_Path + 'one_day_log_turnover_difference.png',
                                                             training_one_day_log_turnover_difference_list, False)
                        PictureUtil.create_histogram_picture('五日对数成交量差', HmmConfig.Save_Hmm_Histogram_Path + 'five_day_log_turnover_difference.png',
                                                             training_five_day_log_turnover_difference_list, False)
                        PictureUtil.create_histogram_picture('一日对数收盘价差', HmmConfig.Save_Hmm_Histogram_Path + 'one_day_log_close_price_difference.png',
                                                             training_one_day_log_close_price_difference_list, False)
                        PictureUtil.create_histogram_picture('五日对数收盘价差', HmmConfig.Save_Hmm_Histogram_Path + 'five_day_log_close_price_difference.png',
                                                             training_five_day_log_close_price_difference_list, False)
                        PictureUtil.create_histogram_picture('当日对数高低价差',
                                                             HmmConfig.Save_Hmm_Histogram_Path + 'five_day_log_highest_price_lowest_price_difference.png',
                                                             training_five_day_log_highest_price_lowest_price_difference_list,
                                                             True)

                    # 转换为ndarray和float
                    training_one_day_log_turnover_difference_ndarray = np.array(
                        training_one_day_log_turnover_difference_list).astype('float')
                    training_five_day_log_turnover_difference_ndarray = np.array(
                        training_five_day_log_turnover_difference_list).astype('float')
                    training_one_day_log_close_price_difference_ndarray = np.array(
                        training_one_day_log_close_price_difference_list).astype('float')
                    training_five_day_log_close_price_difference_difference_ndarray = np.array(
                        training_five_day_log_close_price_difference_list).astype('float')
                    training_five_day_log_highest_price_lowest_price_difference_ndarray = np.array(
                        training_five_day_log_highest_price_lowest_price_difference_list).astype('float')

                    # Box-Cox转换
                    training_five_day_log_highest_price_lowest_price_difference_ndarray, _ = boxcox(
                        training_five_day_log_highest_price_lowest_price_difference_ndarray + 1, lmbda=None, alpha=None)

                    # Z-score标准化
                    z_scaler = preprocessing.StandardScaler()
                    training_one_day_log_turnover_difference_ndarray = z_scaler.fit_transform(
                        training_one_day_log_turnover_difference_ndarray.reshape(-1, 1))
                    training_five_day_log_turnover_difference_ndarray = z_scaler.fit_transform(
                        training_five_day_log_turnover_difference_ndarray.reshape(-1, 1))
                    training_one_day_log_close_price_difference_ndarray = z_scaler.fit_transform(
                        training_one_day_log_close_price_difference_ndarray.reshape(-1, 1))
                    training_five_day_log_close_price_difference_difference_ndarray = z_scaler.fit_transform(
                        training_five_day_log_close_price_difference_difference_ndarray.reshape(-1, 1))
                    training_five_day_log_highest_price_lowest_price_difference_ndarray = z_scaler.fit_transform(
                        training_five_day_log_highest_price_lowest_price_difference_ndarray.reshape(-1, 1))

                    # 合并成训练数据
                    X = np.column_stack(
                        [training_one_day_log_turnover_difference_ndarray,
                         training_five_day_log_turnover_difference_ndarray,
                         training_one_day_log_close_price_difference_ndarray,
                         training_five_day_log_close_price_difference_difference_ndarray,
                         training_five_day_log_highest_price_lowest_price_difference_ndarray])

                    # print(np.sum(X, axis=1))
                    # 将数据送入模型，进行隐马尔科夫预测
                    model = GaussianHMM(n_components=HmmConfig.Status_Number, covariance_type="full", n_iter=2000).fit(X)
                    transmat_init = np.ones((HmmConfig.Status_Number, HmmConfig.Status_Number)) / HmmConfig.Status_Number
                    model.transmat_ = transmat_init
                    # print(model.means_)
                    # print(DatetimeUtil.datetime_to_str(training_end_date, DatetimeFormat.Date_Format_With_Line))
                    # if DatetimeUtil.datetime_to_str(training_end_date, DatetimeFormat.Date_Format_With_Line) == "2014-05-01":
                    #     print(np.sum(training_one_day_log_turnover_difference_ndarray))
                    #     print(np.sum(training_five_day_log_turnover_difference_ndarray))
                    #     print(np.sum(training_one_day_log_close_price_difference_ndarray))
                    #     print(np.sum(training_five_day_log_close_price_difference_difference_ndarray))
                    #     print(np.sum(training_five_day_log_highest_price_lowest_price_difference_ndarray))
                    # print(training_one_day_log_turnover_difference_ndarray[len(training_one_day_log_turnover_difference_ndarray) - 1])
                    # print(np.sum(model.transmat_))
                    hidden_state_ndarray = model.predict(X)

                    # 打印包含状态的折线图
                    if HmmConfig.Save_Line_Picture:
                        training_transaction_date_dataframe = pd.DataFrame(training_transaction_date_list)
                        training_close_price_dataframe = pd.DataFrame(training_close_price_list)
                        plt.figure(figsize=(25, 18))
                        for i in range(model.n_components):
                            pos = (hidden_state_ndarray == i)
                            plt.plot_date(training_transaction_date_dataframe[pos], training_close_price_dataframe[pos],
                                          'o',
                                          label='hidden state %d' % i, lw=2)
                            plt.legend()
                        # plt.show()
                        fig = plt.gcf()  # 获取当前figure
                        plt.savefig(HmmConfig.Save_Profit_Loss_Rate_And_Close_Price_Path + commodity_future_info.code + ".png")
                        plt.close(fig)  # 关闭传入的 figure 对象

                    # 每一种状态都测试一遍：当前交易日开仓，第二天如果状态相同测持有，否则平仓
                #     training_result_ndarray = np.zeros((HmmConfig.Status_Number, 2))
                #     for training_status in range(0, HmmConfig.Status_Number):
                #         Logger.info("当前测试的状态为[%d]", training_status)
                #
                #         # 当前收益率，初始化为100%
                #         training_current_profit: float = 100.00
                #         # 是否持仓
                #         training_holding: bool = False
                #         # 买入价
                #         training_buying_price: float
                #         # 记录所有状态收益率的二维数组
                #         training_profit_ndarray = np.zeros(
                #             (HmmConfig.Status_Number, len(training_transaction_date_list) + 1))
                #         # 初始化记录所有状态收益率的二维数组
                #         training_profit_ndarray[:, 0].fill(training_current_profit)
                #
                #         for index, hidden_state in enumerate(hidden_state_ndarray):
                #             # 开仓
                #             if training_holding is False and training_status == hidden_state:
                #                 training_buying_price = float(training_close_price_list[index])
                #                 training_holding = True
                #             # 平仓
                #             if training_holding is True and training_status != hidden_state:
                #                 if float(training_close_price_list[index]) - training_buying_price != 0:
                #                     training_current_profit = training_current_profit * (
                #                             1 + (float(
                #                         training_close_price_list[index]) - training_buying_price) / training_buying_price)
                #                 training_profit_ndarray[HmmConfig.Status_Number - 1, index + 1] = training_current_profit
                #                 training_holding = False
                #             # 空仓或持仓状态时
                #             training_profit_ndarray[HmmConfig.Status_Number - 1, index] = training_current_profit
                #
                #         Logger.info("状态为[%d]，最后的收益率为[%f]", training_status, training_current_profit)
                #         training_result_ndarray[training_status, 0] = training_status
                #         training_result_ndarray[training_status, 1] = training_current_profit
                #
                #     # 确定哪个状态做多，哪个状态做空
                #     # 做多的状态
                #     do_long_status: int
                #     # 做空的状态
                #     do_short_status: int
                #     # 初始化最大值
                #     max_profit: float = sys.float_info.min
                #     # 初始化最小值
                #     min_profit: float = sys.float_info.max
                #     for training_result in training_result_ndarray:
                #         if training_result[1] > max_profit:
                #             do_long_status = training_result[0]
                #             max_profit = training_result[1]
                #     for training_result in training_result_ndarray:
                #         if training_result[1] < min_profit:
                #             do_short_status = training_result[0]
                #             min_profit = training_result[1]
                #     Logger.info("状态为[%d]时做多，状态为[%d]时做空", do_long_status, do_short_status)
                #
                #     # 用训练数据模拟真实交易
                #     if hidden_state_ndarray[len(hidden_state_ndarray) - 1] == do_long_status:
                #         Logger.info("当前的状态是[" + str(do_long_status) + "]，因此属于多头态势")
                #
                #         if testing_holding_short is True:
                #             # 如果持有空单，则平仓空单
                #             Logger.info("当前持有空单，所以平仓空单")
                #
                #             testing_close_sell_price = training_close_price_list[len(training_close_price_list) - 1]
                #             testing_close_sell_date = training_transaction_date_list[
                #                 len(training_transaction_date_list) - 1]
                #
                #             testing_current_profit = testing_current_profit * (
                #                     1 + (float(testing_open_sell_price) - float(testing_close_sell_price)) / float(
                #                 testing_open_sell_price))
                #             testing_last_profit_and_loss_rate = testing_current_profit
                #             testing_profit_ndarray[HmmConfig.Status_Number - 1][testing_index] = testing_current_profit
                #
                #             testing_holding_short = False
                #
                #             # 平仓空单
                #             query_kwargs = {
                #                 "code": commodity_future_info.code,
                #                 "sell_date": testing_open_sell_date
                #             }
                #             new_attrs_kwargs = {
                #                 "buy_date": testing_close_sell_date,
                #                 "buy_price": testing_close_sell_price,
                #                 "profit_loss": testing_open_sell_price - testing_close_sell_price,
                #                 "accumulative_profit_loss": testing_current_profit
                #             }
                #             self.model_hmm_dao.update_batch_by_query(query_kwargs, dict(),
                #                                                      new_attrs_kwargs)
                #
                #         elif testing_holding_long is False:
                #             # 如果没有持有多单，则开仓多单
                #             Logger.info("当前没有持有多单，所以开仓多单")
                #
                #             testing_open_buying_price = training_close_price_list[len(training_close_price_list) - 1]
                #             testing_open_buying_date = training_transaction_date_list[
                #                 len(training_transaction_date_list) - 1]
                #
                #             testing_profit_ndarray[HmmConfig.Status_Number - 1][
                #                 testing_index] = testing_last_profit_and_loss_rate
                #
                #             testing_holding_long = True
                #
                #             # 开仓多单
                #             model_hmm = ModelHmm()
                #             model_hmm.code = commodity_future_info.code
                #             model_hmm.buy_date = testing_open_buying_date
                #             model_hmm.buy_price = testing_open_buying_price
                #             model_hmm.direction = Direction.Up
                #             self.model_hmm_dao.save(model_hmm)
                #         else:
                #             # 如果已经持有多单，则继续持有多单
                #             Logger.info("当前已经持有多单，所以继续持有多单")
                #
                #             testing_profit_ndarray[HmmConfig.Status_Number - 1][
                #                 testing_index] = testing_last_profit_and_loss_rate
                #
                #     elif hidden_state_ndarray[len(hidden_state_ndarray) - 1] == do_short_status:
                #         Logger.info("当前的状态是[" + str(do_short_status) + "]，因此空头态势")
                #
                #         if testing_holding_long is True:
                #             # 如果持有多单，则平仓多单
                #             Logger.info("当前持有多单，所以平仓多单")
                #
                #             testing_close_buying_price = training_close_price_list[len(training_close_price_list) - 1]
                #             testing_close_buying_date = training_transaction_date_list[
                #                 len(training_transaction_date_list) - 1]
                #
                #             testing_current_profit = testing_current_profit * (
                #                     1 + (
                #                     float(testing_close_buying_price) - float(testing_open_buying_price)) / float(
                #                 testing_open_buying_price))
                #             testing_profit_ndarray[HmmConfig.Status_Number - 1][testing_index] = testing_current_profit
                #             testing_last_profit_and_loss_rate = testing_current_profit
                #
                #             testing_holding_long = False
                #
                #             # 平仓多单
                #             query_kwargs = {
                #                 "code": commodity_future_info.code,
                #                 "buy_date": testing_open_buying_date
                #             }
                #             new_attrs_kwargs = {
                #                 "sell_date": testing_close_buying_date,
                #                 "sell_price": testing_close_buying_price,
                #                 "profit_loss": testing_close_buying_price - testing_open_buying_price,
                #                 "accumulative_profit_loss": testing_current_profit
                #             }
                #             self.model_hmm_dao.update_batch_by_query(query_kwargs, dict(),
                #                                                      new_attrs_kwargs)
                #
                #         elif testing_holding_short is False:
                #             # 如果没有持有空单，则开空单
                #             Logger.info("当前没有持有空单，所以开仓空单")
                #
                #             testing_open_sell_price = training_close_price_list[len(training_close_price_list) - 1]
                #             testing_open_sell_date = training_transaction_date_list[len(training_transaction_date_list) - 1]
                #
                #             testing_profit_ndarray[HmmConfig.Status_Number - 1][
                #                 testing_index] = testing_last_profit_and_loss_rate
                #
                #             testing_holding_short = True
                #
                #             # 开仓空单
                #             model_hmm = ModelHmm()
                #             model_hmm.code = commodity_future_info.code
                #             model_hmm.sell_date = testing_open_sell_date
                #             model_hmm.sell_price = testing_open_sell_price
                #             model_hmm.direction = Direction.Down
                #             self.model_hmm_dao.save(model_hmm)
                #         else:
                #             # 如果已经持有空单，则继续持有空单
                #             Logger.info("当前已经持有空单，所以继续持有空单")
                #
                #             testing_profit_ndarray[HmmConfig.Status_Number - 1][
                #                 testing_index] = testing_last_profit_and_loss_rate
                #
                #     else:
                #         Logger.info(
                #             "当前的状态是[" + str(hidden_state_ndarray[len(hidden_state_ndarray) - 1]) + "]，不做任何操作")
                #         if testing_holding_long is True:
                #             Logger.info("之前的多单继续持有")
                #         if testing_holding_short is True:
                #             Logger.info("之前的空单继续持有")
                #
                #         testing_profit_ndarray[
                #             HmmConfig.Status_Number - 1, testing_index] = testing_last_profit_and_loss_rate
                #
                #     Logger.info("当前的日期为[" + DatetimeUtil.datetime_to_str(training_transaction_date_list[
                #                                                                    len(training_transaction_date_list) - 1],
                #                                                                DatetimeFormat.Date_Format_With_Line) + "]，当前的收益率：" +
                #                 testing_profit_ndarray[HmmConfig.Status_Number - 1][testing_index].astype(str))
                #
                #     testing_index = testing_index + 1
                #
                # Logger.info("期货[" + commodity_future_info.code + "]经过测试之后的收益率为[" +
                #             testing_profit_ndarray[HmmConfig.Status_Number - 1][testing_index].astype(str) + "]")
            except Exception as e:
                Logger.error("在期货[" + commodity_future_info.code + "]上使用hmm算法时，报错[" + str(e) + "]")
                continue

    def training_all_commodity_future_with_many_eigenvalue(self):
        """
        hmm算法，测试所有期货（主力连续）数据：生成直方图、在训练数据集中学习，在测试数据集中测试。（使用尽可能多的特征值）
        """

        # 查询所有期货信息
        # commodity_future_info_list: list = self.commodity_future_info_dao.find_all()
        commodity_future_info_list: list = self.commodity_future_info_dao.find_for_hmm()
        for commodity_future_info in commodity_future_info_list:
            Logger.info("开始测试期货[" + commodity_future_info.code + commodity_future_info.name + "]")

            try:
                # 查询某个期货的全部记录
                commodity_future_date_data_list = list(CommodityFutureDateData.objects.filter(
                    Q(code=commodity_future_info.code) & Q(open_interest__isnull=False) &
                    Q(rising_and_falling_amount__isnull=False) & Q(price_change__isnull=False) &
                    Q(ma5__isnull=False) & Q(ma10__isnull=False) & Q(ma20__isnull=False) & Q(ma60__isnull=False) &
                    Q(ma120__isnull=False) & Q(ma250__isnull=False) & Q(ema12__isnull=False) & Q(ema26__isnull=False) &
                    Q(dif__isnull=False) & Q(dea__isnull=False) & Q(rsv__isnull=False) & Q(k__isnull=False) &
                    Q(d__isnull=False) & Q(up__isnull=False) & Q(mb__isnull=False) & Q(dn__isnull=False) &
                    Q(ha_open_price__isnull=False) & Q(ha_close_price__isnull=False) & Q(
                        ha_highest_price__isnull=False) &
                    Q(ha_lowest_price__isnull=False) & Q(bias5__isnull=False) & Q(bias10__isnull=False) &
                    Q(bias20__isnull=False) & Q(bias60__isnull=False) & Q(bias120__isnull=False) &
                    Q(bias250__isnull=False) & Q(variance5__isnull=False) & Q(variance10__isnull=False) &
                    Q(variance20__isnull=False) & Q(variance60__isnull=False) & Q(variance120__isnull=False) &
                    Q(variance250__isnull=False) & Q(macd__isnull=False)).order_by('transaction_date'))

                # 判断某个期货的交易记录数是否满足要求
                if len(commodity_future_date_data_list) < HmmConfig.Training_Data_Number:
                    Logger.warning("期货[" + commodity_future_info.code + "]的记录数量为" + str(len(
                        commodity_future_info_list)) + "，不足" + str(
                        HmmConfig.Training_Data_Number) + "个，因此不做测试")
                    continue

                # 当前收益率，初始化为100%
                testing_current_profit: float = 100.00
                # 是否持有多单
                testing_holding_long: bool = False
                # 是否持有空单
                testing_holding_short: bool = False
                # 开多仓价格
                testing_open_buying_price: float
                # 开多仓日期
                testing_open_buying_date: datetime
                # 平多仓价格
                testing_close_buying_price: float
                # 平多仓日期
                testing_close_buying_date: datetime
                # 开空仓价格
                testing_open_sell_price: float
                # 开空仓日期
                testing_open_sell_date: datetime
                # 平空仓价格
                testing_close_sell_price: float
                # 平空仓日期
                testing_close_selling_price: datetime
                # 记录所有状态收益率的二维数组
                testing_profit_ndarray = np.zeros(
                    (HmmConfig.Status_Number, len(commodity_future_date_data_list) - HmmConfig.Training_Data_Number))
                # 初始化记录所有状态收益率的二维数组
                testing_profit_ndarray[:, 0].fill(testing_current_profit)
                # 测试的索引
                testing_index: int = 0
                # 测试时，上一个交易日的收益率
                testing_last_profit_and_loss_rate: float = 100.00

                for training_index, commodity_future_date_data in enumerate(commodity_future_date_data_list):
                    training_index = training_index + 1
                    if training_index < HmmConfig.Training_Data_Number + HmmConfig.Logarithm_Date_Number:
                        continue

                    # 训练样本开始时间
                    training_begin_date: datetime.date = commodity_future_date_data_list[
                        training_index - HmmConfig.Training_Data_Number].transaction_date
                    # 训练样本结束时间
                    training_end_date: datetime.date = commodity_future_date_data.transaction_date
                    Logger.info("训练样本的开始时间是[" + DatetimeUtil.datetime_to_str(training_begin_date,
                                                                                       DatetimeFormat.Date_Format_With_Line) +
                                "]，结束时间是[" + DatetimeUtil.datetime_to_str(training_end_date,
                                                                               DatetimeFormat.Date_Format_With_Line) + "]")

                    # 获取总体样本数据
                    (training_open_price_list,
                     training_close_price_list,
                     training_highest_price_list,
                     training_lowest_price_list,
                     training_turnover_list,
                     training_transaction_date_list,
                     # training_open_interest_list,
                     training_rising_and_falling_amount_list,
                     training_price_change_list,
                     training_ma5_list,
                     training_ma10_list,
                     training_ma20_list,
                     training_ma60_list,
                     training_ma120_list,
                     training_ma250_list,
                     training_ema12_list,
                     training_ema26_list,
                     training_dif_list,
                     training_dea_list,
                     training_rsv_list,
                     training_k_list,
                     training_d_list,
                     training_up_list,
                     training_mb_list,
                     training_dn_list,
                     training_ha_open_price_list,
                     training_ha_close_price_list,
                     training_ha_highest_price_list,
                     training_ha_lowest_price_list,
                     training_bias5_list,
                     training_bias10_list,
                     training_bias20_list,
                     training_bias60_list,
                     training_bias120_list,
                     training_bias250_list,
                     training_variance5_list,
                     training_variance10_list,
                     training_variance20_list,
                     training_variance60_list,
                     training_variance120_list,
                     training_variance250_list,
                     training_macd_list, training_total_number) = (
                        self.commodity_future_date_data_dao.prepare_for_hmm_with_many_eigenvalue(
                            commodity_future_info.code, training_begin_date, training_end_date))

                    original_training_close_price_list = training_close_price_list

                    # 归一化
                    training_open_price_list = MathUtil.normalize(training_open_price_list)[0]
                    training_close_price_list = MathUtil.normalize(training_close_price_list)[0]
                    training_highest_price_list = MathUtil.normalize(training_highest_price_list)[0]
                    training_lowest_price_list = MathUtil.normalize(training_lowest_price_list)[0]
                    training_turnover_list = MathUtil.normalize(training_turnover_list)[0]
                    # training_open_interest_list = MathUtil.normalize(training_open_interest_list)[0]
                    training_rising_and_falling_amount_list = \
                        MathUtil.normalize(training_rising_and_falling_amount_list)[0]
                    training_price_change_list = MathUtil.normalize(training_price_change_list)[0]
                    training_ma5_list = MathUtil.normalize(training_ma5_list)[0]
                    training_ma10_list = MathUtil.normalize(training_ma10_list)[0]
                    training_ma20_list = MathUtil.normalize(training_ma20_list)[0]
                    training_ma60_list = MathUtil.normalize(training_ma60_list)[0]
                    training_ma120_list = MathUtil.normalize(training_ma120_list)[0]
                    training_ma250_list = MathUtil.normalize(training_ma250_list)[0]
                    training_ema12_list = MathUtil.normalize(training_ema12_list)[0]
                    training_ema26_list = MathUtil.normalize(training_ema26_list)[0]
                    training_dif_list = MathUtil.normalize(training_dif_list)[0]
                    training_dea_list = MathUtil.normalize(training_dea_list)[0]
                    training_rsv_list = MathUtil.normalize(training_rsv_list)[0]
                    training_k_list = MathUtil.normalize(training_k_list)[0]
                    training_d_list = MathUtil.normalize(training_d_list)[0]
                    training_up_list = MathUtil.normalize(training_up_list)[0]
                    training_mb_list = MathUtil.normalize(training_mb_list)[0]
                    training_dn_list = MathUtil.normalize(training_dn_list)[0]
                    training_ha_open_price_list = MathUtil.normalize(training_ha_open_price_list)[0]
                    training_ha_close_price_list = MathUtil.normalize(training_ha_close_price_list)[0]
                    training_ha_highest_price_list = MathUtil.normalize(training_ha_highest_price_list)[0]
                    training_ha_lowest_price_list = MathUtil.normalize(training_ha_lowest_price_list)[0]
                    training_bias5_list = MathUtil.normalize(training_bias5_list)[0]
                    training_bias10_list = MathUtil.normalize(training_bias10_list)[0]
                    training_bias20_list = MathUtil.normalize(training_bias20_list)[0]
                    training_bias60_list = MathUtil.normalize(training_bias60_list)[0]
                    training_bias120_list = MathUtil.normalize(training_bias120_list)[0]
                    training_bias250_list = MathUtil.normalize(training_bias250_list)[0]
                    training_variance5_list = MathUtil.normalize(training_variance5_list)[0]
                    training_variance10_list = MathUtil.normalize(training_variance10_list)[0]
                    training_variance20_list = MathUtil.normalize(training_variance20_list)[0]
                    training_variance60_list = MathUtil.normalize(training_variance60_list)[0]
                    training_variance120_list = MathUtil.normalize(training_variance120_list)[0]
                    training_variance250_list = MathUtil.normalize(training_variance250_list)[0]
                    training_macd_list = MathUtil.normalize(training_macd_list)[0]

                    # 转换为ndarray和float
                    training_open_price_ndarray = np.array(training_open_price_list).astype('float')
                    training_close_price_ndarray = np.array(training_close_price_list).astype('float')
                    training_highest_price_ndarray = np.array(training_highest_price_list).astype('float')
                    training_lowest_price_ndarray = np.array(training_lowest_price_list).astype('float')
                    training_turnover_ndarray = np.array(training_turnover_list).astype('float')
                    # training_open_interest_ndarray = np.array(training_open_interest_list).astype('float')
                    training_rising_and_falling_amount_ndarray = np.array(
                        training_rising_and_falling_amount_list).astype(
                        'float')
                    training_price_change_ndarray = np.array(training_price_change_list).astype('float')
                    training_ma5_ndarray = np.array(training_ma5_list).astype('float')
                    training_ma10_ndarray = np.array(training_ma10_list).astype('float')
                    training_ma20_ndarray = np.array(training_ma20_list).astype('float')
                    training_ma60_ndarray = np.array(training_ma60_list).astype('float')
                    training_ma120_ndarray = np.array(training_ma120_list).astype('float')
                    training_ma250_ndarray = np.array(training_ma250_list).astype('float')
                    training_ema12_ndarray = np.array(training_ema12_list).astype('float')
                    training_ema26_ndarray = np.array(training_ema26_list).astype('float')
                    training_dif_ndarray = np.array(training_dif_list).astype('float')
                    training_dea_ndarray = np.array(training_dea_list).astype('float')
                    training_rsv_ndarray = np.array(training_rsv_list).astype('float')
                    training_k_ndarray = np.array(training_k_list).astype('float')
                    training_d_ndarray = np.array(training_d_list).astype('float')
                    training_up_ndarray = np.array(training_up_list).astype('float')
                    training_mb_ndarray = np.array(training_mb_list).astype('float')
                    training_dn_ndarray = np.array(training_dn_list).astype('float')
                    training_ha_open_price_ndarray = np.array(training_ha_open_price_list).astype('float')
                    training_ha_close_price_ndarray = np.array(training_ha_close_price_list).astype('float')
                    training_ha_highest_price_ndarray = np.array(training_ha_highest_price_list).astype('float')
                    training_ha_lowest_price_ndarray = np.array(training_ha_lowest_price_list).astype('float')
                    training_bias5_ndarray = np.array(training_bias5_list).astype('float')
                    training_bias10_ndarray = np.array(training_bias10_list).astype('float')
                    training_bias20_ndarray = np.array(training_bias20_list).astype('float')
                    training_bias60_ndarray = np.array(training_bias60_list).astype('float')
                    training_bias120_ndarray = np.array(training_bias120_list).astype('float')
                    training_bias250_ndarray = np.array(training_bias250_list).astype('float')
                    training_variance5_ndarray = np.array(training_variance5_list).astype('float')
                    training_variance10_ndarray = np.array(training_variance10_list).astype('float')
                    training_variance20_ndarray = np.array(training_variance20_list).astype('float')
                    training_variance60_ndarray = np.array(training_variance60_list).astype('float')
                    training_variance120_ndarray = np.array(training_variance120_list).astype('float')
                    training_variance250_ndarray = np.array(training_variance250_list).astype('float')
                    training_macd_ndarray = np.array(training_macd_list).astype('float')

                    # Box-Cox转换
                    training_open_price_ndarray, _ = boxcox(training_open_price_ndarray + 1, lmbda=None, alpha=None)
                    training_close_price_ndarray, _ = boxcox(training_close_price_ndarray + 1, lmbda=None, alpha=None)
                    training_highest_price_ndarray, _ = boxcox(training_highest_price_ndarray + 1, lmbda=None,
                                                               alpha=None)
                    training_lowest_price_ndarray, _ = boxcox(training_lowest_price_ndarray + 1, lmbda=None, alpha=None)
                    training_turnover_ndarray, _ = boxcox(training_turnover_ndarray + 1, lmbda=None, alpha=None)
                    # training_open_interest_ndarray, _ = boxcox(training_open_interest_ndarray + 1, lmbda=None, alpha=None)
                    training_rising_and_falling_amount_ndarray, _ = boxcox(
                        training_rising_and_falling_amount_ndarray + 1,
                        lmbda=None, alpha=None)
                    training_price_change_ndarray, _ = boxcox(training_price_change_ndarray + 1, lmbda=None, alpha=None)
                    training_ma5_ndarray, _ = boxcox(training_ma5_ndarray + 1, lmbda=None, alpha=None)
                    training_ma10_ndarray, _ = boxcox(training_ma10_ndarray + 1, lmbda=None, alpha=None)
                    training_ma20_ndarray, _ = boxcox(training_ma20_ndarray + 1, lmbda=None, alpha=None)
                    training_ma60_ndarray, _ = boxcox(training_ma60_ndarray + 1, lmbda=None, alpha=None)
                    training_ma120_ndarray, _ = boxcox(training_ma120_ndarray + 1, lmbda=None, alpha=None)
                    training_ma250_ndarray, _ = boxcox(training_ma250_ndarray + 1, lmbda=None, alpha=None)
                    training_ema12_ndarray, _ = boxcox(training_ema12_ndarray + 1, lmbda=None, alpha=None)
                    training_ema26_ndarray, _ = boxcox(training_ema26_ndarray + 1, lmbda=None, alpha=None)
                    training_dif_ndarray, _ = boxcox(training_dif_ndarray + 1, lmbda=None, alpha=None)
                    training_dea_ndarray, _ = boxcox(training_dea_ndarray + 1, lmbda=None, alpha=None)
                    training_rsv_ndarray, _ = boxcox(training_rsv_ndarray + 1, lmbda=None, alpha=None)
                    training_k_ndarray, _ = boxcox(training_k_ndarray + 1, lmbda=None, alpha=None)
                    training_d_ndarray, _ = boxcox(training_d_ndarray + 1, lmbda=None, alpha=None)
                    training_up_ndarray, _ = boxcox(training_up_ndarray + 1, lmbda=None, alpha=None)
                    training_mb_ndarray, _ = boxcox(training_mb_ndarray + 1, lmbda=None, alpha=None)
                    training_dn_ndarray, _ = boxcox(training_dn_ndarray + 1, lmbda=None, alpha=None)
                    training_ha_open_price_ndarray, _ = boxcox(training_ha_open_price_ndarray + 1, lmbda=None,
                                                               alpha=None)
                    training_ha_close_price_ndarray, _ = boxcox(training_ha_close_price_ndarray + 1, lmbda=None,
                                                                alpha=None)
                    training_ha_highest_price_ndarray, _ = boxcox(training_ha_highest_price_ndarray + 1, lmbda=None,
                                                                  alpha=None)
                    training_ha_lowest_price_ndarray, _ = boxcox(training_ha_lowest_price_ndarray + 1, lmbda=None,
                                                                 alpha=None)
                    training_bias5_ndarray, _ = boxcox(training_bias5_ndarray + 1, lmbda=None, alpha=None)
                    training_bias10_ndarray, _ = boxcox(training_bias10_ndarray + 1, lmbda=None, alpha=None)
                    training_bias20_ndarray, _ = boxcox(training_bias20_ndarray + 1, lmbda=None, alpha=None)
                    training_bias60_ndarray, _ = boxcox(training_bias60_ndarray + 1, lmbda=None, alpha=None)
                    training_bias120_ndarray, _ = boxcox(training_bias120_ndarray + 1, lmbda=None, alpha=None)
                    training_bias250_ndarray, _ = boxcox(training_bias250_ndarray + 1, lmbda=None, alpha=None)
                    training_variance5_ndarray, _ = boxcox(training_variance5_ndarray + 1, lmbda=None, alpha=None)
                    training_variance10_ndarray, _ = boxcox(training_variance10_ndarray + 1, lmbda=None, alpha=None)
                    training_variance20_ndarray, _ = boxcox(training_variance20_ndarray + 1, lmbda=None, alpha=None)
                    training_variance60_ndarray, _ = boxcox(training_variance60_ndarray + 1, lmbda=None, alpha=None)
                    training_variance120_ndarray, _ = boxcox(training_variance120_ndarray + 1, lmbda=None, alpha=None)
                    training_variance250_ndarray, _ = boxcox(training_variance250_ndarray + 1, lmbda=None, alpha=None)
                    training_macd_ndarray, _ = boxcox(training_macd_ndarray + 1, lmbda=None, alpha=None)

                    # 生成直方图
                    if HmmConfig.Save_Histogram_Picture:
                        PictureUtil.create_histogram_picture('开盘价对数',
                                                             HmmConfig.Save_Hmm_Histogram_Path + 'open_price_log.png',
                                                             training_open_price_ndarray.tolist(), False)
                        PictureUtil.create_histogram_picture('收盘价对数',
                                                             HmmConfig.Save_Hmm_Histogram_Path + 'close_price_log.png',
                                                             training_close_price_ndarray.tolist(), False)
                        PictureUtil.create_histogram_picture('最高价对数',
                                                             HmmConfig.Save_Hmm_Histogram_Path + 'highest_price_log.png',
                                                             training_highest_price_ndarray.tolist(), False)
                        PictureUtil.create_histogram_picture('最低价对数',
                                                             HmmConfig.Save_Hmm_Histogram_Path + 'lowest_price_log.png',
                                                             training_lowest_price_ndarray.tolist(), False)
                        PictureUtil.create_histogram_picture('成交量对数',
                                                             HmmConfig.Save_Hmm_Histogram_Path + 'turnover_log.png',
                                                             training_turnover_ndarray.tolist(), True)
                        # PictureUtil.create_histogram_picture('持仓量对数', HmmConfig.Save_Hmm_Histogram_Path + 'open_interest_log.png',
                        #                                      training_open_interest_ndarray.tolist(), True)
                        PictureUtil.create_histogram_picture('涨跌额对数',
                                                             HmmConfig.Save_Hmm_Histogram_Path + 'rising_and_falling_amount_log.png',
                                                             training_rising_and_falling_amount_ndarray.tolist(), True)
                        PictureUtil.create_histogram_picture('涨跌幅对数',
                                                             HmmConfig.Save_Hmm_Histogram_Path + 'price_change_log.png',
                                                             training_price_change_ndarray.tolist(), True)
                        PictureUtil.create_histogram_picture('5日均线对数',
                                                             HmmConfig.Save_Hmm_Histogram_Path + 'ma5_log.png',
                                                             training_ma5_ndarray.tolist(), True)
                        PictureUtil.create_histogram_picture('10日均线对数',
                                                             HmmConfig.Save_Hmm_Histogram_Path + 'ma10_log.png',
                                                             training_ma10_ndarray.tolist(), True)
                        PictureUtil.create_histogram_picture('20日均线对数',
                                                             HmmConfig.Save_Hmm_Histogram_Path + 'ma20_log.png',
                                                             training_ma20_ndarray.tolist(), True)
                        PictureUtil.create_histogram_picture('60日均线对数',
                                                             HmmConfig.Save_Hmm_Histogram_Path + 'HmmConfig.Save_Histogram_Picture + ma60_log.png',
                                                             training_ma60_ndarray.tolist(), True)
                        PictureUtil.create_histogram_picture('120日均线对数',
                                                             HmmConfig.Save_Hmm_Histogram_Path + 'ma120_log.png',
                                                             training_ma120_ndarray.tolist(), True)
                        PictureUtil.create_histogram_picture('250日均线对数',
                                                             HmmConfig.Save_Hmm_Histogram_Path + 'ma250_log.png',
                                                             training_ma250_ndarray.tolist(), True)
                        PictureUtil.create_histogram_picture('MACD的ema12对数',
                                                             HmmConfig.Save_Hmm_Histogram_Path + 'ema12_log.png',
                                                             training_ema12_ndarray.tolist(), True)
                        PictureUtil.create_histogram_picture('MACD的ema26对数',
                                                             HmmConfig.Save_Hmm_Histogram_Path + 'ema26_log.png',
                                                             training_ema26_ndarray.tolist(), True)
                        PictureUtil.create_histogram_picture('MACD的dif对数',
                                                             HmmConfig.Save_Hmm_Histogram_Path + 'dif_log.png',
                                                             training_dif_ndarray.tolist(), True)
                        PictureUtil.create_histogram_picture('MACD的dea对数',
                                                             HmmConfig.Save_Hmm_Histogram_Path + 'dea_log.png',
                                                             training_dea_ndarray.tolist(), True)
                        PictureUtil.create_histogram_picture('KD的rsv对数',
                                                             HmmConfig.Save_Hmm_Histogram_Path + 'rsv_log.png',
                                                             training_rsv_ndarray.tolist(), True)
                        PictureUtil.create_histogram_picture('KD的k对数',
                                                             HmmConfig.Save_Hmm_Histogram_Path + 'k_log.png',
                                                             training_k_ndarray.tolist(), True)
                        PictureUtil.create_histogram_picture('KD的d对数',
                                                             HmmConfig.Save_Hmm_Histogram_Path + 'd_log.png',
                                                             training_d_ndarray.tolist(), True)
                        PictureUtil.create_histogram_picture('布林带上轨对数',
                                                             HmmConfig.Save_Hmm_Histogram_Path + 'up_log.png',
                                                             training_up_ndarray.tolist(), True)
                        PictureUtil.create_histogram_picture('布林带中轨对数',
                                                             HmmConfig.Save_Hmm_Histogram_Path + 'mb_log.png',
                                                             training_mb_ndarray.tolist(), True)
                        PictureUtil.create_histogram_picture('布林带下轨对数',
                                                             HmmConfig.Save_Hmm_Histogram_Path + 'dn_log.png',
                                                             training_dn_ndarray.tolist(), True)
                        PictureUtil.create_histogram_picture('HeiKinAshi开盘价对数',
                                                             HmmConfig.Save_Hmm_Histogram_Path + 'ha_open_price_log.png',
                                                             training_ha_open_price_ndarray.tolist(), True)
                        PictureUtil.create_histogram_picture('HeiKinAshi收盘价对数',
                                                             HmmConfig.Save_Hmm_Histogram_Path + 'ha_close_price_log.png',
                                                             training_ha_close_price_ndarray.tolist(), True)
                        PictureUtil.create_histogram_picture('HeiKinAshi最高价对数',
                                                             HmmConfig.Save_Hmm_Histogram_Path + 'ha_highest_price_log.png',
                                                             training_ha_highest_price_ndarray.tolist(), True)
                        PictureUtil.create_histogram_picture('HeiKinAshi最低价对数',
                                                             HmmConfig.Save_Hmm_Histogram_Path + 'ha_lowest_price_log.png',
                                                             training_ha_lowest_price_ndarray.tolist(), True)
                        PictureUtil.create_histogram_picture('5日bias对数',
                                                             HmmConfig.Save_Hmm_Histogram_Path + 'bias5_log.png',
                                                             training_bias5_ndarray.tolist(), True)
                        PictureUtil.create_histogram_picture('10日bias对数',
                                                             HmmConfig.Save_Hmm_Histogram_Path + 'bias10_log.png',
                                                             training_bias10_ndarray.tolist(), True)
                        PictureUtil.create_histogram_picture('20日bias对数',
                                                             HmmConfig.Save_Hmm_Histogram_Path + 'bias20_log.png',
                                                             training_bias20_ndarray.tolist(), True)
                        PictureUtil.create_histogram_picture('60日bias对数',
                                                             HmmConfig.Save_Hmm_Histogram_Path + 'bias60_log.png',
                                                             training_bias60_ndarray.tolist(), True)
                        PictureUtil.create_histogram_picture('120日bias对数',
                                                             HmmConfig.Save_Hmm_Histogram_Path + 'bias120_log.png',
                                                             training_bias120_ndarray.tolist(), True)
                        PictureUtil.create_histogram_picture('250日bias对数',
                                                             HmmConfig.Save_Hmm_Histogram_Path + 'bias250_log.png',
                                                             training_bias250_ndarray.tolist(), True)
                        PictureUtil.create_histogram_picture('5日variance对数',
                                                             HmmConfig.Save_Hmm_Histogram_Path + 'variance5_log.png',
                                                             training_variance5_ndarray.tolist(), True)
                        PictureUtil.create_histogram_picture('10日variance对数',
                                                             HmmConfig.Save_Hmm_Histogram_Path + 'variance10_log.png',
                                                             training_variance10_ndarray.tolist(), True)
                        PictureUtil.create_histogram_picture('20日variance对数',
                                                             HmmConfig.Save_Hmm_Histogram_Path + 'variance20_log.png',
                                                             training_variance20_ndarray.tolist(), True)
                        PictureUtil.create_histogram_picture('60日variance对数',
                                                             HmmConfig.Save_Hmm_Histogram_Path + 'variance60_log.png',
                                                             training_variance60_ndarray.tolist(), True)
                        PictureUtil.create_histogram_picture('120日variance对数',
                                                             HmmConfig.Save_Hmm_Histogram_Path + 'variance120_log.png',
                                                             training_variance120_ndarray.tolist(), True)
                        PictureUtil.create_histogram_picture('250日variance对数',
                                                             HmmConfig.Save_Hmm_Histogram_Path + 'variance250_log.png',
                                                             training_variance250_ndarray.tolist(), True)
                        PictureUtil.create_histogram_picture('macd对数',
                                                             HmmConfig.Save_Hmm_Histogram_Path + 'macd_log.png',
                                                             training_macd_ndarray.tolist(), True)

                    # Z-score标准化
                    z_scaler = preprocessing.StandardScaler()
                    training_open_price_ndarray = z_scaler.fit_transform(training_open_price_ndarray.reshape(-1, 1))
                    training_close_price_ndarray = z_scaler.fit_transform(training_close_price_ndarray.reshape(-1, 1))
                    training_highest_price_ndarray = z_scaler.fit_transform(
                        training_highest_price_ndarray.reshape(-1, 1))
                    training_lowest_price_ndarray = z_scaler.fit_transform(training_lowest_price_ndarray.reshape(-1, 1))
                    training_turnover_ndarray = z_scaler.fit_transform(training_turnover_ndarray.reshape(-1, 1))
                    # training_open_interest_ndarray = z_scaler.fit_transform(training_open_interest_ndarray.reshape(-1, 1))
                    training_rising_and_falling_amount_ndarray = z_scaler.fit_transform(
                        training_rising_and_falling_amount_ndarray.reshape(-1, 1))
                    training_price_change_ndarray = z_scaler.fit_transform(training_price_change_ndarray.reshape(-1, 1))
                    training_ma5_ndarray = z_scaler.fit_transform(training_ma5_ndarray.reshape(-1, 1))
                    training_ma10_ndarray = z_scaler.fit_transform(training_ma10_ndarray.reshape(-1, 1))
                    training_ma20_ndarray = z_scaler.fit_transform(training_ma20_ndarray.reshape(-1, 1))
                    training_ma60_ndarray = z_scaler.fit_transform(training_ma60_ndarray.reshape(-1, 1))
                    training_ma120_ndarray = z_scaler.fit_transform(training_ma120_ndarray.reshape(-1, 1))
                    training_ma250_ndarray = z_scaler.fit_transform(training_ma250_ndarray.reshape(-1, 1))
                    training_ema12_ndarray = z_scaler.fit_transform(training_ema12_ndarray.reshape(-1, 1))
                    training_ema26_ndarray = z_scaler.fit_transform(training_ema26_ndarray.reshape(-1, 1))
                    training_dif_ndarray = z_scaler.fit_transform(training_dif_ndarray.reshape(-1, 1))
                    training_dea_ndarray = z_scaler.fit_transform(training_dea_ndarray.reshape(-1, 1))
                    training_rsv_ndarray = z_scaler.fit_transform(training_rsv_ndarray.reshape(-1, 1))
                    training_k_ndarray = z_scaler.fit_transform(training_k_ndarray.reshape(-1, 1))
                    training_d_ndarray = z_scaler.fit_transform(training_d_ndarray.reshape(-1, 1))
                    training_up_ndarray = z_scaler.fit_transform(training_up_ndarray.reshape(-1, 1))
                    training_mb_ndarray = z_scaler.fit_transform(training_mb_ndarray.reshape(-1, 1))
                    training_dn_ndarray = z_scaler.fit_transform(training_dn_ndarray.reshape(-1, 1))
                    training_ha_open_price_ndarray = z_scaler.fit_transform(
                        training_ha_open_price_ndarray.reshape(-1, 1))
                    training_ha_close_price_ndarray = z_scaler.fit_transform(
                        training_ha_close_price_ndarray.reshape(-1, 1))
                    training_ha_highest_price_ndarray = z_scaler.fit_transform(
                        training_ha_highest_price_ndarray.reshape(-1, 1))
                    training_ha_lowest_price_ndarray = z_scaler.fit_transform(
                        training_ha_lowest_price_ndarray.reshape(-1, 1))
                    training_bias5_ndarray = z_scaler.fit_transform(training_bias5_ndarray.reshape(-1, 1))
                    training_bias10_ndarray = z_scaler.fit_transform(training_bias10_ndarray.reshape(-1, 1))
                    training_bias20_ndarray = z_scaler.fit_transform(training_bias20_ndarray.reshape(-1, 1))
                    training_bias60_ndarray = z_scaler.fit_transform(training_bias60_ndarray.reshape(-1, 1))
                    training_bias120_ndarray = z_scaler.fit_transform(training_bias120_ndarray.reshape(-1, 1))
                    training_bias250_ndarray = z_scaler.fit_transform(training_bias250_ndarray.reshape(-1, 1))
                    training_variance5_ndarray = z_scaler.fit_transform(training_variance5_ndarray.reshape(-1, 1))
                    training_variance10_ndarray = z_scaler.fit_transform(training_variance10_ndarray.reshape(-1, 1))
                    training_variance20_ndarray = z_scaler.fit_transform(training_variance20_ndarray.reshape(-1, 1))
                    training_variance60_ndarray = z_scaler.fit_transform(training_variance60_ndarray.reshape(-1, 1))
                    training_variance120_ndarray = z_scaler.fit_transform(training_variance120_ndarray.reshape(-1, 1))
                    training_variance250_ndarray = z_scaler.fit_transform(training_variance250_ndarray.reshape(-1, 1))
                    training_macd_ndarray = z_scaler.fit_transform(training_macd_ndarray.reshape(-1, 1))

                    # ndarray转换为list
                    training_open_price_list = training_open_price_ndarray.tolist()
                    training_close_price_list = list(chain.from_iterable(training_close_price_ndarray.tolist()))
                    training_highest_price_list = training_highest_price_ndarray.tolist()
                    training_lowest_price_list = training_lowest_price_ndarray.tolist()
                    training_turnover_list = training_turnover_ndarray.tolist()
                    # training_open_interest_list = training_open_interest_ndarray.tolist()
                    training_rising_and_falling_amount_list = training_rising_and_falling_amount_ndarray.tolist()
                    training_price_change_list = training_price_change_ndarray.tolist()
                    training_ma5_list = training_ma5_ndarray.tolist()
                    training_ma10_list = training_ma10_ndarray.tolist()
                    training_ma20_list = training_ma20_ndarray.tolist()
                    training_ma60_list = training_ma60_ndarray.tolist()
                    training_ma120_list = training_ma120_ndarray.tolist()
                    training_ma250_list = training_ma250_ndarray.tolist()
                    training_ema12_list = training_ema12_ndarray.tolist()
                    training_ema26_list = training_ema26_ndarray.tolist()
                    training_dif_list = training_dif_ndarray.tolist()
                    training_dea_list = training_dea_ndarray.tolist()
                    training_rsv_list = training_rsv_ndarray.tolist()
                    training_k_list = training_k_ndarray.tolist()
                    training_d_list = training_d_ndarray.tolist()
                    training_up_list = training_up_ndarray.tolist()
                    training_mb_list = training_mb_ndarray.tolist()
                    training_dn_list = training_dn_ndarray.tolist()
                    training_ha_open_price_list = training_ha_open_price_ndarray.tolist()
                    training_ha_close_price_list = training_ha_close_price_ndarray.tolist()
                    training_ha_highest_price_list = training_ha_highest_price_ndarray.tolist()
                    training_ha_lowest_price_list = training_ha_lowest_price_ndarray.tolist()
                    training_bias5_list = training_bias5_ndarray.tolist()
                    training_bias10_list = training_bias10_ndarray.tolist()
                    training_bias20_list = training_bias20_ndarray.tolist()
                    training_bias60_list = training_bias60_ndarray.tolist()
                    training_bias120_list = training_bias120_ndarray.tolist()
                    training_bias250_list = training_bias250_ndarray.tolist()
                    training_variance5_list = training_variance5_ndarray.tolist()
                    training_variance10_list = training_variance10_ndarray.tolist()
                    training_variance20_list = training_variance20_ndarray.tolist()
                    training_variance60_list = training_variance60_ndarray.tolist()
                    training_variance120_list = training_variance120_ndarray.tolist()
                    training_variance250_list = training_variance250_ndarray.tolist()
                    training_macd_list = training_macd_ndarray.tolist()

                    # 合并成训练数据
                    X = np.column_stack(
                        [training_open_price_ndarray, training_close_price_ndarray, training_highest_price_ndarray,
                         training_lowest_price_ndarray, training_turnover_ndarray,  # training_open_interest_ndarray,
                         training_rising_and_falling_amount_ndarray, training_price_change_ndarray,
                         training_ma5_ndarray,
                         training_ma10_ndarray, training_ma20_ndarray, training_ma60_ndarray, training_ma120_ndarray,
                         training_ma250_ndarray, training_ema12_ndarray, training_ema26_ndarray, training_dif_ndarray,
                         training_dea_ndarray, training_rsv_ndarray, training_k_ndarray, training_d_ndarray,
                         training_up_ndarray, training_mb_ndarray, training_dn_ndarray, training_ha_open_price_ndarray,
                         training_ha_close_price_ndarray, training_ha_highest_price_ndarray,
                         training_ha_lowest_price_ndarray, training_bias5_ndarray, training_bias10_ndarray,
                         training_bias20_ndarray, training_bias60_ndarray, training_bias120_ndarray,
                         training_bias250_ndarray, training_variance5_ndarray, training_variance10_ndarray,
                         training_variance20_ndarray, training_variance60_ndarray, training_variance120_ndarray,
                         training_variance250_ndarray, training_macd_ndarray])

                    # print(np.sum(X, axis=1))
                    # 将数据送入模型，进行隐马尔科夫预测
                    model = GaussianHMM(n_components=HmmConfig.Status_Number, covariance_type="full", n_iter=2000).fit(
                        X)
                    transmat_init = np.ones(
                        (HmmConfig.Status_Number, HmmConfig.Status_Number)) / HmmConfig.Status_Number
                    model.transmat_ = transmat_init
                    # print(model.means_)
                    # print(DatetimeUtil.datetime_to_str(training_end_date, DatetimeFormat.Date_Format_With_Line))
                    # if DatetimeUtil.datetime_to_str(training_end_date, DatetimeFormat.Date_Format_With_Line) == "2014-05-01":
                    #     print(np.sum(training_one_day_log_turnover_difference_ndarray))
                    #     print(np.sum(training_five_day_log_turnover_difference_ndarray))
                    #     print(np.sum(training_one_day_log_close_price_difference_ndarray))
                    #     print(np.sum(training_five_day_log_close_price_difference_difference_ndarray))
                    #     print(np.sum(training_five_day_log_highest_price_lowest_price_difference_ndarray))
                    # print(training_one_day_log_turnover_difference_ndarray[len(training_one_day_log_turnover_difference_ndarray) - 1])
                    # print(np.sum(model.transmat_))
                    hidden_state_ndarray = model.predict(X)

                    # 打印包含状态的折线图
                    if HmmConfig.Save_Line_Picture:
                        training_transaction_date_dataframe = pd.DataFrame(training_transaction_date_list)
                        training_close_price_dataframe = pd.DataFrame(training_close_price_list)
                        plt.figure(figsize=(25, 18))
                        for i in range(model.n_components):
                            pos = (hidden_state_ndarray == i)
                            plt.plot_date(training_transaction_date_dataframe[pos], training_close_price_dataframe[pos],
                                          'o',
                                          label='hidden state %d' % i, lw=2)
                            plt.legend()
                        # plt.show()
                        fig = plt.gcf()  # 获取当前figure
                        plt.savefig(HmmConfig.Save_Profit_Loss_Rate_And_Close_Price_Path + commodity_future_info.code + ".png")
                        plt.close(fig)  # 关闭传入的 figure 对象

                    # 每一种状态都测试一遍：当前交易日开仓，第二天如果状态相同测持有，否则平仓
                #     training_result_ndarray = np.zeros((HmmConfig.Status_Number, 2))
                #     for training_status in range(0, HmmConfig.Status_Number):
                #         Logger.info("当前测试的状态为[%d]", training_status)
                #
                #         # 当前收益率，初始化为100%
                #         training_current_profit: float = 100.00
                #         # 是否持仓
                #         training_holding: bool = False
                #         # 买入价
                #         training_buying_price: float
                #         # 记录所有状态收益率的二维数组
                #         training_profit_ndarray = np.zeros(
                #             (HmmConfig.Status_Number, len(training_transaction_date_list) + 1))
                #         # 初始化记录所有状态收益率的二维数组
                #         training_profit_ndarray[:, 0].fill(training_current_profit)
                #
                #         for index, hidden_state in enumerate(hidden_state_ndarray):
                #             # 开仓
                #             if training_holding is False and training_status == hidden_state:
                #                 training_buying_price = float(training_close_price_list[index])
                #                 training_holding = True
                #             # 平仓
                #             if training_holding is True and training_status != hidden_state:
                #                 if float(training_close_price_list[index]) - training_buying_price != 0:
                #                     training_current_profit = training_current_profit * (
                #                             1 + (float(
                #                         training_close_price_list[
                #                             index]) - training_buying_price) / training_buying_price)
                #                 training_profit_ndarray[
                #                     HmmConfig.Status_Number - 1, index + 1] = training_current_profit
                #                 training_holding = False
                #             # 空仓或持仓状态时
                #             training_profit_ndarray[HmmConfig.Status_Number - 1, index] = training_current_profit
                #
                #         Logger.info("状态为[%d]，最后的收益率为[%f]", training_status, training_current_profit)
                #         training_result_ndarray[training_status, 0] = training_status
                #         training_result_ndarray[training_status, 1] = training_current_profit
                #
                #     # 确定哪个状态做多，哪个状态做空
                #     # 做多的状态
                #     do_long_status: int
                #     # 做空的状态
                #     do_short_status: int
                #     # 初始化最大值
                #     max_profit: float = sys.float_info.min
                #     # 初始化最小值
                #     min_profit: float = sys.float_info.max
                #     for training_result in training_result_ndarray:
                #         if training_result[1] > max_profit:
                #             do_long_status = training_result[0]
                #             max_profit = training_result[1]
                #     for training_result in training_result_ndarray:
                #         if training_result[1] < min_profit:
                #             do_short_status = training_result[0]
                #             min_profit = training_result[1]
                #     Logger.info("状态为[%d]时做多，状态为[%d]时做空", do_long_status, do_short_status)
                #
                #     # 用训练数据模拟真实交易
                #     if hidden_state_ndarray[len(hidden_state_ndarray) - 1] == do_long_status:
                #         Logger.info("当前的状态是[" + str(do_long_status) + "]，因此属于多头态势")
                #
                #         if testing_holding_short is True:
                #             # 如果持有空单，则平仓空单
                #             Logger.info("当前持有空单，所以平仓空单")
                #
                #             testing_close_sell_price = original_training_close_price_list[
                #                 len(training_close_price_list) - 1]
                #             testing_close_sell_date = training_transaction_date_list[
                #                 len(training_transaction_date_list) - 1]
                #
                #             testing_current_profit = testing_current_profit * (
                #                     1 + (float(testing_open_sell_price) - float(testing_close_sell_price)) / float(
                #                 testing_open_sell_price))
                #             testing_last_profit_and_loss_rate = testing_current_profit
                #             testing_profit_ndarray[HmmConfig.Status_Number - 1][testing_index] = testing_current_profit
                #
                #             testing_holding_short = False
                #
                #             # 平仓空单
                #             query_kwargs = {
                #                 "code": commodity_future_info.code,
                #                 "sell_date": testing_open_sell_date
                #             }
                #             new_attrs_kwargs = {
                #                 "buy_date": testing_close_sell_date,
                #                 "buy_price": testing_close_sell_price,
                #                 "profit_loss": testing_open_sell_price - testing_close_sell_price,
                #                 "accumulative_profit_loss": testing_current_profit
                #             }
                #             self.model_hmm_dao.update_batch_by_query(query_kwargs, dict(),
                #                                                      new_attrs_kwargs)
                #
                #         elif testing_holding_long is False:
                #             # 如果没有持有多单，则开仓多单
                #             Logger.info("当前没有持有多单，所以开仓多单")
                #
                #             testing_open_buying_price = original_training_close_price_list[
                #                 len(training_close_price_list) - 1]
                #             testing_open_buying_date = training_transaction_date_list[
                #                 len(training_transaction_date_list) - 1]
                #
                #             testing_profit_ndarray[HmmConfig.Status_Number - 1][
                #                 testing_index] = testing_last_profit_and_loss_rate
                #
                #             testing_holding_long = True
                #
                #             # 开仓多单
                #             model_hmm = ModelHmm()
                #             model_hmm.code = commodity_future_info.code
                #             model_hmm.buy_date = testing_open_buying_date
                #             model_hmm.buy_price = testing_open_buying_price
                #             model_hmm.direction = Direction.Up
                #             self.model_hmm_dao.save(model_hmm)
                #         else:
                #             # 如果已经持有多单，则继续持有多单
                #             Logger.info("当前已经持有多单，所以继续持有多单")
                #
                #             testing_profit_ndarray[HmmConfig.Status_Number - 1][
                #                 testing_index] = testing_last_profit_and_loss_rate
                #
                #     elif hidden_state_ndarray[len(hidden_state_ndarray) - 1] == do_short_status:
                #         Logger.info("当前的状态是[" + str(do_short_status) + "]，因此空头态势")
                #
                #         if testing_holding_long is True:
                #             # 如果持有多单，则平仓多单
                #             Logger.info("当前持有多单，所以平仓多单")
                #
                #             testing_close_buying_price = original_training_close_price_list[
                #                 len(training_close_price_list) - 1]
                #             testing_close_buying_date = training_transaction_date_list[
                #                 len(training_transaction_date_list) - 1]
                #
                #             testing_current_profit = testing_current_profit * (
                #                     1 + (
                #                     float(testing_close_buying_price) - float(testing_open_buying_price)) / float(
                #                 testing_open_buying_price))
                #             testing_profit_ndarray[HmmConfig.Status_Number - 1][testing_index] = testing_current_profit
                #             testing_last_profit_and_loss_rate = testing_current_profit
                #
                #             testing_holding_long = False
                #
                #             # 平仓多单
                #             query_kwargs = {
                #                 "code": commodity_future_info.code,
                #                 "buy_date": testing_open_buying_date
                #             }
                #             new_attrs_kwargs = {
                #                 "sell_date": testing_close_buying_date,
                #                 "sell_price": testing_close_buying_price,
                #                 "profit_loss": testing_close_buying_price - testing_open_buying_price,
                #                 "accumulative_profit_loss": testing_current_profit
                #             }
                #             self.model_hmm_dao.update_batch_by_query(query_kwargs, dict(),
                #                                                      new_attrs_kwargs)
                #
                #         elif testing_holding_short is False:
                #             # 如果没有持有空单，则开空单
                #             Logger.info("当前没有持有空单，所以开仓空单")
                #
                #             testing_open_sell_price = original_training_close_price_list[
                #                 len(training_close_price_list) - 1]
                #             testing_open_sell_date = training_transaction_date_list[
                #                 len(training_transaction_date_list) - 1]
                #
                #             testing_profit_ndarray[HmmConfig.Status_Number - 1][
                #                 testing_index] = testing_last_profit_and_loss_rate
                #
                #             testing_holding_short = True
                #
                #             # 开仓空单
                #             model_hmm = ModelHmm()
                #             model_hmm.code = commodity_future_info.code
                #             model_hmm.sell_date = testing_open_sell_date
                #             model_hmm.sell_price = testing_open_sell_price
                #             model_hmm.direction = Direction.Down
                #             self.model_hmm_dao.save(model_hmm)
                #         else:
                #             # 如果已经持有空单，则继续持有空单
                #             Logger.info("当前已经持有空单，所以继续持有空单")
                #
                #             testing_profit_ndarray[HmmConfig.Status_Number - 1][
                #                 testing_index] = testing_last_profit_and_loss_rate
                #
                #     else:
                #         Logger.info(
                #             "当前的状态是[" + str(
                #                 hidden_state_ndarray[len(hidden_state_ndarray) - 1]) + "]，不做任何操作")
                #         if testing_holding_long is True:
                #             Logger.info("之前的多单继续持有")
                #         if testing_holding_short is True:
                #             Logger.info("之前的空单继续持有")
                #
                #         testing_profit_ndarray[
                #             HmmConfig.Status_Number - 1, testing_index] = testing_last_profit_and_loss_rate
                #
                #     Logger.info("当前的日期为[" + DatetimeUtil.datetime_to_str(training_transaction_date_list[
                #                                                                    len(training_transaction_date_list) - 1],
                #                                                                DatetimeFormat.Date_Format_With_Line) + "]，当前的收益率：" +
                #                 testing_profit_ndarray[HmmConfig.Status_Number - 1][testing_index].astype(str))
                #
                #     testing_index = testing_index + 1
                #
                # Logger.info("期货[" + commodity_future_info.code + "]经过测试之后的收益率为[" +
                #             testing_profit_ndarray[HmmConfig.Status_Number - 1][testing_index].astype(str) + "]")

            except Exception as e:
                Logger.error("在期货[" + commodity_future_info.code + "]上使用hmm算法时，报错[" + str(e) + "]")
                continue

    def training_all_etf_transaction_data_with_many_eigenvalue(self):
        """
        hmm算法，测试所有ETF数据：生成直方图、在训练数据集中学习，在测试数据集中测试。（使用尽可能多的特征值）
        """

        # 查询所有ETF信息
        etf_transaction_data_list: list = self.etf_transaction_data_dao.find_for_hmm()
        for etf_transaction_data in etf_transaction_data_list:
            Logger.info("开始测试ETF[" + etf_transaction_data.code_ + etf_transaction_data.name + "]")

            # try:
            # 查询某个ETF的全部记录
            etf_transaction_data_for_hmm_list = self.etf_transaction_data_dao.prepare_for_hmm_with_many_eigenvalue(etf_transaction_data.code_)

            # 判断某个ETF的交易记录数是否满足要求
            if len(etf_transaction_data_for_hmm_list) < HmmConfig.Training_Data_Number:
                Logger.warning("ETF[" + etf_transaction_data.code_ + "]的记录数量为" + str(len(
                    etf_transaction_data_for_hmm_list)) + "，不足" + str(HmmConfig.Training_Data_Number) + "个，因此不做测试")
                continue

            # 当前收益率，初始化为100%
            testing_current_profit: float = 100.00
            # 是否持有多单
            testing_holding_long: bool = False
            # 是否持有空单
            testing_holding_short: bool = False
            # 开多仓价格
            testing_open_buying_price: float
            # 开多仓日期
            testing_open_buying_date: datetime
            # 平多仓价格
            testing_close_buying_price: float
            # 平多仓日期
            testing_close_buying_date: datetime
            # 记录所有状态收益率的二维数组
            testing_profit_ndarray = np.zeros(
                (HmmConfig.Status_Number, len(etf_transaction_data_for_hmm_list) - HmmConfig.Training_Data_Number))
            # 初始化记录所有状态收益率的二维数组
            testing_profit_ndarray[:, 0].fill(testing_current_profit)
            # 测试的索引
            testing_index: int = 0
            # 测试时，上一个交易日的收益率
            testing_last_profit_and_loss_rate: float = 100.00

            for training_index, etf_transaction_data in enumerate(etf_transaction_data_for_hmm_list):
                training_index = training_index + 1
                if training_index < HmmConfig.Training_Data_Number + HmmConfig.Logarithm_Date_Number:
                    continue

                # 训练样本开始时间
                training_begin_date: datetime.date = etf_transaction_data_for_hmm_list[
                    training_index - HmmConfig.Training_Data_Number].date_
                # 训练样本结束时间
                training_end_date: datetime.date = etf_transaction_data.date_
                Logger.info("训练样本的开始时间是[" + DatetimeUtil.datetime_to_str(training_begin_date,
                                                                                   DatetimeFormat.Date_Format_With_Line) +
                            "]，结束时间是[" + DatetimeUtil.datetime_to_str(training_end_date,
                                                                           DatetimeFormat.Date_Format_With_Line) + "]")

                # 获取总体样本数据
                (training_date_list,
                 training_open_price_list,
                 training_close_price_list,
                 training_highest_price_list,
                 training_lowest_price_list,
                 training_change_amount_list,
                 training_change_range_list,
                 training_volume_list,
                 training_turnover_list,
                 training_ma5_list,
                 training_ma10_list,
                 training_ma20_list,
                 training_ma60_list,
                 training_ma120_list,
                 training_ma250_list,
                 training_ha_open_price_list,
                 training_ha_close_price_list,
                 training_ha_highest_price_list,
                 training_ha_lowest_price_list,
                 training_bias5_list,
                 training_bias10_list,
                 training_bias20_list,
                 training_bias60_list,
                 training_bias120_list,
                 training_bias250_list,
                 training_ema12_list,
                 training_ema26_list,
                 training_dif_list,
                 training_dea_list,
                 training_rsv_list,
                 training_k_list,
                 training_d_list,
                 training_up_list,
                 training_mb_list,
                 training_dn_list, training_total_number) = (
                    self.etf_transaction_data_dao.prepare_for_hmm_with_date_with_many_eigenvalue(
                        etf_transaction_data.code_, training_begin_date, training_end_date))

                original_training_close_price_list = training_close_price_list

                # 归一化
                training_open_price_list = MathUtil.normalize(training_open_price_list)[0]
                training_close_price_list = MathUtil.normalize(training_close_price_list)[0]
                training_highest_price_list = MathUtil.normalize(training_highest_price_list)[0]
                training_lowest_price_list = MathUtil.normalize(training_lowest_price_list)[0]
                training_change_amount_list = MathUtil.normalize(training_change_amount_list)[0]
                training_change_range_list = MathUtil.normalize(training_change_range_list)[0]
                training_volume_list = MathUtil.normalize(training_volume_list)[0]
                training_turnover_list = MathUtil.normalize(training_turnover_list)[0]
                training_ma5_list = MathUtil.normalize(training_ma5_list)[0]
                training_ma10_list = MathUtil.normalize(training_ma10_list)[0]
                training_ma20_list = MathUtil.normalize(training_ma20_list)[0]
                training_ma60_list = MathUtil.normalize(training_ma60_list)[0]
                training_ma120_list = MathUtil.normalize(training_ma120_list)[0]
                training_ma250_list = MathUtil.normalize(training_ma250_list)[0]
                training_ha_open_price_list = MathUtil.normalize(training_ha_open_price_list)[0]
                training_ha_close_price_list = MathUtil.normalize(training_ha_close_price_list)[0]
                training_ha_highest_price_list = MathUtil.normalize(training_ha_highest_price_list)[0]
                training_ha_lowest_price_list = MathUtil.normalize(training_ha_lowest_price_list)[0]
                training_bias5_list = MathUtil.normalize(training_bias5_list)[0]
                training_bias10_list = MathUtil.normalize(training_bias10_list)[0]
                training_bias20_list = MathUtil.normalize(training_bias20_list)[0]
                training_bias60_list = MathUtil.normalize(training_bias60_list)[0]
                training_bias120_list = MathUtil.normalize(training_bias120_list)[0]
                training_bias250_list = MathUtil.normalize(training_bias250_list)[0]
                training_ema12_list = MathUtil.normalize(training_ema12_list)[0]
                training_ema26_list = MathUtil.normalize(training_ema26_list)[0]
                training_dif_list = MathUtil.normalize(training_dif_list)[0]
                training_dea_list = MathUtil.normalize(training_dea_list)[0]
                training_rsv_list = MathUtil.normalize(training_rsv_list)[0]
                training_k_list = MathUtil.normalize(training_k_list)[0]
                training_d_list = MathUtil.normalize(training_d_list)[0]

                # 转换为ndarray和float
                training_open_price_ndarray = np.array(training_open_price_list).astype('float')
                training_close_price_ndarray = np.array(training_close_price_list).astype('float')
                training_highest_price_ndarray = np.array(training_highest_price_list).astype('float')
                training_lowest_price_ndarray = np.array(training_lowest_price_list).astype('float')
                training_change_amount_ndarray = np.array(training_change_amount_list).astype('float')
                training_change_range_ndarray = np.array(training_change_range_list).astype('float')
                training_volume_ndarray = np.array(training_volume_list).astype('float')
                training_turnover_ndarray = np.array(training_turnover_list).astype('float')
                training_ma5_ndarray = np.array(training_ma5_list).astype('float')
                training_ma10_ndarray = np.array(training_ma10_list).astype('float')
                training_ma20_ndarray = np.array(training_ma20_list).astype('float')
                training_ma60_ndarray = np.array(training_ma60_list).astype('float')
                training_ma120_ndarray = np.array(training_ma120_list).astype('float')
                training_ma250_ndarray = np.array(training_ma250_list).astype('float')
                training_ha_open_price_ndarray = np.array(training_ha_open_price_list).astype('float')
                training_ha_close_price_ndarray = np.array(training_ha_close_price_list).astype('float')
                training_ha_highest_price_ndarray = np.array(training_ha_highest_price_list).astype('float')
                training_ha_lowest_price_ndarray = np.array(training_ha_lowest_price_list).astype('float')
                training_bias5_ndarray = np.array(training_bias5_list).astype('float')
                training_bias10_ndarray = np.array(training_bias10_list).astype('float')
                training_bias20_ndarray = np.array(training_bias20_list).astype('float')
                training_bias60_ndarray = np.array(training_bias60_list).astype('float')
                training_bias120_ndarray = np.array(training_bias120_list).astype('float')
                training_bias250_ndarray = np.array(training_bias250_list).astype('float')
                training_ema12_ndarray = np.array(training_ema12_list).astype('float')
                training_ema26_ndarray = np.array(training_ema26_list).astype('float')
                training_dif_ndarray = np.array(training_dif_list).astype('float')
                training_dea_ndarray = np.array(training_dea_list).astype('float')
                training_rsv_ndarray = np.array(training_rsv_list).astype('float')
                training_k_ndarray = np.array(training_k_list).astype('float')
                training_d_ndarray = np.array(training_d_list).astype('float')

                # Box-Cox转换
                training_open_price_ndarray, _ = boxcox(training_open_price_ndarray + 1, lmbda=None, alpha=None)
                training_close_price_ndarray, _ = boxcox(training_close_price_ndarray + 1, lmbda=None, alpha=None)
                training_highest_price_ndarray, _ = boxcox(training_highest_price_ndarray + 1, lmbda=None,
                                                           alpha=None)
                training_lowest_price_ndarray, _ = boxcox(training_lowest_price_ndarray + 1, lmbda=None, alpha=None)
                training_change_amount_ndarray, _ = boxcox(training_change_amount_ndarray + 1, lmbda=None,
                                                           alpha=None)
                training_change_range_ndarray, _ = boxcox(training_change_range_ndarray + 1, lmbda=None, alpha=None)
                training_volume_ndarray, _ = boxcox(training_volume_ndarray + 1, lmbda=None, alpha=None)
                training_turnover_ndarray, _ = boxcox(training_turnover_ndarray + 1, lmbda=None, alpha=None)
                training_ma5_ndarray, _ = boxcox(training_ma5_ndarray + 1, lmbda=None, alpha=None)
                training_ma10_ndarray, _ = boxcox(training_ma10_ndarray + 1, lmbda=None, alpha=None)
                training_ma20_ndarray, _ = boxcox(training_ma20_ndarray + 1, lmbda=None, alpha=None)
                training_ma60_ndarray, _ = boxcox(training_ma60_ndarray + 1, lmbda=None, alpha=None)
                training_ma120_ndarray, _ = boxcox(training_ma120_ndarray + 1, lmbda=None, alpha=None)
                training_ma250_ndarray, _ = boxcox(training_ma250_ndarray + 1, lmbda=None, alpha=None)
                training_ha_open_price_ndarray, _ = boxcox(training_ha_open_price_ndarray + 1, lmbda=None,
                                                           alpha=None)
                training_ha_close_price_ndarray, _ = boxcox(training_ha_close_price_ndarray + 1, lmbda=None,
                                                            alpha=None)
                training_ha_highest_price_ndarray, _ = boxcox(training_ha_highest_price_ndarray + 1, lmbda=None,
                                                              alpha=None)
                training_ha_lowest_price_ndarray, _ = boxcox(training_ha_lowest_price_ndarray + 1, lmbda=None,
                                                             alpha=None)
                training_bias5_ndarray, _ = boxcox(training_bias5_ndarray + 1, lmbda=None, alpha=None)
                training_bias10_ndarray, _ = boxcox(training_bias10_ndarray + 1, lmbda=None, alpha=None)
                training_bias20_ndarray, _ = boxcox(training_bias20_ndarray + 1, lmbda=None, alpha=None)
                training_bias60_ndarray, _ = boxcox(training_bias60_ndarray + 1, lmbda=None, alpha=None)
                training_bias120_ndarray, _ = boxcox(training_bias120_ndarray + 1, lmbda=None, alpha=None)
                training_bias250_ndarray, _ = boxcox(training_bias250_ndarray + 1, lmbda=None, alpha=None)
                training_ema12_ndarray, _ = boxcox(training_ema12_ndarray + 1, lmbda=None, alpha=None)
                training_ema26_ndarray, _ = boxcox(training_ema26_ndarray + 1, lmbda=None, alpha=None)
                training_dif_ndarray, _ = boxcox(training_dif_ndarray + 1, lmbda=None, alpha=None)
                training_dea_ndarray, _ = boxcox(training_dea_ndarray + 1, lmbda=None, alpha=None)
                training_rsv_ndarray, _ = boxcox(training_rsv_ndarray + 1, lmbda=None, alpha=None)
                training_k_ndarray, _ = boxcox(training_k_ndarray + 1, lmbda=None, alpha=None)
                training_d_ndarray, _ = boxcox(training_d_ndarray + 1, lmbda=None, alpha=None)

                # 生成直方图
                if HmmConfig.Save_Histogram_Picture:
                    PictureUtil.create_histogram_picture('开盘价对数',
                                                         HmmConfig.Save_Histogram_Picture + 'open_price_log.png',
                                                         training_open_price_ndarray.tolist(), False)
                    PictureUtil.create_histogram_picture('收盘价对数',
                                                         HmmConfig.Save_Histogram_Picture + 'close_price_log.png',
                                                         training_close_price_ndarray.tolist(), False)
                    PictureUtil.create_histogram_picture('最高价对数',
                                                         HmmConfig.Save_Histogram_Picture + 'highest_price_log.png',
                                                         training_highest_price_ndarray.tolist(), False)
                    PictureUtil.create_histogram_picture('最低价对数',
                                                         HmmConfig.Save_Histogram_Picture + 'lowest_price_log.png',
                                                         training_lowest_price_ndarray.tolist(), False)
                    PictureUtil.create_histogram_picture('涨跌额对数',
                                                         HmmConfig.Save_Histogram_Picture + 'change_amount_log.png',
                                                         training_change_amount_ndarray.tolist(), True)
                    PictureUtil.create_histogram_picture('涨跌幅对数',
                                                         HmmConfig.Save_Histogram_Picture + 'change_range_log.png',
                                                         training_change_range_ndarray.tolist(), True)
                    PictureUtil.create_histogram_picture('成交量对数',
                                                         HmmConfig.Save_Histogram_Picture + 'volume_log.png',
                                                         training_volume_ndarray.tolist(), True)
                    PictureUtil.create_histogram_picture('成交额对数',
                                                         HmmConfig.Save_Histogram_Picture + 'turnover_log.png',
                                                         training_turnover_ndarray.tolist(), True)
                    PictureUtil.create_histogram_picture('5日均线对数',
                                                         HmmConfig.Save_Histogram_Picture + 'ma5_log.png',
                                                         training_ma5_ndarray.tolist(), True)
                    PictureUtil.create_histogram_picture('10日均线对数',
                                                         HmmConfig.Save_Histogram_Picture + 'ma10_log.png',
                                                         training_ma10_ndarray.tolist(), True)
                    PictureUtil.create_histogram_picture('20日均线对数',
                                                         HmmConfig.Save_Histogram_Picture + 'ma20_log.png',
                                                         training_ma20_ndarray.tolist(), True)
                    PictureUtil.create_histogram_picture('60日均线对数',
                                                         'HmmConfig.Save_Histogram_Picture + ma60_log.png',
                                                         training_ma60_ndarray.tolist(), True)
                    PictureUtil.create_histogram_picture('120日均线对数',
                                                         HmmConfig.Save_Histogram_Picture + 'ma120_log.png',
                                                         training_ma120_ndarray.tolist(), True)
                    PictureUtil.create_histogram_picture('250日均线对数',
                                                         HmmConfig.Save_Histogram_Picture + 'ma250_log.png',
                                                         training_ma250_ndarray.tolist(), True)
                    PictureUtil.create_histogram_picture('HeiKinAshi开盘价对数',
                                                         HmmConfig.Save_Histogram_Picture + 'ha_open_price_log.png',
                                                         training_ha_open_price_ndarray.tolist(), True)
                    PictureUtil.create_histogram_picture('HeiKinAshi收盘价对数',
                                                         HmmConfig.Save_Histogram_Picture + 'ha_close_price_log.png',
                                                         training_ha_close_price_ndarray.tolist(), True)
                    PictureUtil.create_histogram_picture('HeiKinAshi最高价对数',
                                                         HmmConfig.Save_Histogram_Picture + 'ha_highest_price_log.png',
                                                         training_ha_highest_price_ndarray.tolist(), True)
                    PictureUtil.create_histogram_picture('HeiKinAshi最低价对数',
                                                         HmmConfig.Save_Histogram_Picture + 'ha_lowest_price_log.png',
                                                         training_ha_lowest_price_ndarray.tolist(), True)
                    PictureUtil.create_histogram_picture('5日bias对数',
                                                         HmmConfig.Save_Histogram_Picture + 'bias5_log.png',
                                                         training_bias5_ndarray.tolist(), True)
                    PictureUtil.create_histogram_picture('10日bias对数',
                                                         HmmConfig.Save_Histogram_Picture + 'bias10_log.png',
                                                         training_bias10_ndarray.tolist(), True)
                    PictureUtil.create_histogram_picture('20日bias对数',
                                                         HmmConfig.Save_Histogram_Picture + 'bias20_log.png',
                                                         training_bias20_ndarray.tolist(), True)
                    PictureUtil.create_histogram_picture('60日bias对数',
                                                         HmmConfig.Save_Histogram_Picture + 'bias60_log.png',
                                                         training_bias60_ndarray.tolist(), True)
                    PictureUtil.create_histogram_picture('120日bias对数',
                                                         HmmConfig.Save_Histogram_Picture + 'bias120_log.png',
                                                         training_bias120_ndarray.tolist(), True)
                    PictureUtil.create_histogram_picture('250日bias对数',
                                                         HmmConfig.Save_Histogram_Picture + 'bias250_log.png',
                                                         training_bias250_ndarray.tolist(), True)
                    PictureUtil.create_histogram_picture('MACD的ema12对数',
                                                         HmmConfig.Save_Histogram_Picture + 'ema12_log.png',
                                                         training_ema12_ndarray.tolist(), True)
                    PictureUtil.create_histogram_picture('MACD的ema26对数',
                                                         HmmConfig.Save_Histogram_Picture + 'ema26_log.png',
                                                         training_ema26_ndarray.tolist(), True)
                    PictureUtil.create_histogram_picture('MACD的dif对数',
                                                         HmmConfig.Save_Histogram_Picture + 'dif_log.png',
                                                         training_dif_ndarray.tolist(), True)
                    PictureUtil.create_histogram_picture('MACD的dea对数',
                                                         HmmConfig.Save_Histogram_Picture + 'dea_log.png',
                                                         training_dea_ndarray.tolist(), True)
                    PictureUtil.create_histogram_picture('KD的rsv对数',
                                                         HmmConfig.Save_Histogram_Picture + 'rsv_log.png',
                                                         training_rsv_ndarray.tolist(), True)
                    PictureUtil.create_histogram_picture('KD的k对数',
                                                         HmmConfig.Save_Histogram_Picture + 'k_log.png',
                                                         training_k_ndarray.tolist(), True)
                    PictureUtil.create_histogram_picture('KD的d对数',
                                                         HmmConfig.Save_Histogram_Picture + 'd_log.png',
                                                         training_d_ndarray.tolist(), True)

                # Z-score标准化
                z_scaler = preprocessing.StandardScaler()
                training_open_price_ndarray = z_scaler.fit_transform(training_open_price_ndarray.reshape(-1, 1))
                training_close_price_ndarray = z_scaler.fit_transform(training_close_price_ndarray.reshape(-1, 1))
                training_highest_price_ndarray = z_scaler.fit_transform(
                    training_highest_price_ndarray.reshape(-1, 1))
                training_lowest_price_ndarray = z_scaler.fit_transform(training_lowest_price_ndarray.reshape(-1, 1))
                training_change_amount_ndarray = z_scaler.fit_transform(
                    training_change_amount_ndarray.reshape(-1, 1))
                training_change_range_ndarray = z_scaler.fit_transform(training_change_range_ndarray.reshape(-1, 1))
                training_volume_ndarray = z_scaler.fit_transform(training_volume_ndarray.reshape(-1, 1))
                training_turnover_ndarray = z_scaler.fit_transform(training_turnover_ndarray.reshape(-1, 1))
                training_ma5_ndarray = z_scaler.fit_transform(training_ma5_ndarray.reshape(-1, 1))
                training_ma10_ndarray = z_scaler.fit_transform(training_ma10_ndarray.reshape(-1, 1))
                training_ma20_ndarray = z_scaler.fit_transform(training_ma20_ndarray.reshape(-1, 1))
                training_ma60_ndarray = z_scaler.fit_transform(training_ma60_ndarray.reshape(-1, 1))
                training_ma120_ndarray = z_scaler.fit_transform(training_ma120_ndarray.reshape(-1, 1))
                training_ma250_ndarray = z_scaler.fit_transform(training_ma250_ndarray.reshape(-1, 1))
                training_ha_open_price_ndarray = z_scaler.fit_transform(
                    training_ha_open_price_ndarray.reshape(-1, 1))
                training_ha_close_price_ndarray = z_scaler.fit_transform(
                    training_ha_close_price_ndarray.reshape(-1, 1))
                training_ha_highest_price_ndarray = z_scaler.fit_transform(
                    training_ha_highest_price_ndarray.reshape(-1, 1))
                training_ha_lowest_price_ndarray = z_scaler.fit_transform(
                    training_ha_lowest_price_ndarray.reshape(-1, 1))
                training_bias5_ndarray = z_scaler.fit_transform(training_bias5_ndarray.reshape(-1, 1))
                training_bias10_ndarray = z_scaler.fit_transform(training_bias10_ndarray.reshape(-1, 1))
                training_bias20_ndarray = z_scaler.fit_transform(training_bias20_ndarray.reshape(-1, 1))
                training_bias60_ndarray = z_scaler.fit_transform(training_bias60_ndarray.reshape(-1, 1))
                training_bias120_ndarray = z_scaler.fit_transform(training_bias120_ndarray.reshape(-1, 1))
                training_bias250_ndarray = z_scaler.fit_transform(training_bias250_ndarray.reshape(-1, 1))
                training_ema12_ndarray = z_scaler.fit_transform(training_ema12_ndarray.reshape(-1, 1))
                training_ema26_ndarray = z_scaler.fit_transform(training_ema26_ndarray.reshape(-1, 1))
                training_dif_ndarray = z_scaler.fit_transform(training_dif_ndarray.reshape(-1, 1))
                training_dea_ndarray = z_scaler.fit_transform(training_dea_ndarray.reshape(-1, 1))
                training_rsv_ndarray = z_scaler.fit_transform(training_rsv_ndarray.reshape(-1, 1))
                training_k_ndarray = z_scaler.fit_transform(training_k_ndarray.reshape(-1, 1))
                training_d_ndarray = z_scaler.fit_transform(training_d_ndarray.reshape(-1, 1))

                # ndarray转换为list
                training_open_price_list = training_open_price_ndarray.tolist()
                training_close_price_list = list(chain.from_iterable(training_close_price_ndarray.tolist()))
                training_highest_price_list = training_highest_price_ndarray.tolist()
                training_lowest_price_list = training_lowest_price_ndarray.tolist()
                training_change_amount_list = training_change_amount_ndarray.tolist()
                training_change_range_list = training_change_range_ndarray.tolist()
                training_volume_list = training_volume_ndarray.tolist()
                training_turnover_list = training_turnover_ndarray.tolist()
                training_ma5_list = training_ma5_ndarray.tolist()
                training_ma10_list = training_ma10_ndarray.tolist()
                training_ma20_list = training_ma20_ndarray.tolist()
                training_ma60_list = training_ma60_ndarray.tolist()
                training_ma120_list = training_ma120_ndarray.tolist()
                training_ma250_list = training_ma250_ndarray.tolist()
                training_ha_open_price_list = training_ha_open_price_ndarray.tolist()
                training_ha_close_price_list = training_ha_close_price_ndarray.tolist()
                training_ha_highest_price_list = training_ha_highest_price_ndarray.tolist()
                training_ha_lowest_price_list = training_ha_lowest_price_ndarray.tolist()
                training_bias5_list = training_bias5_ndarray.tolist()
                training_bias10_list = training_bias10_ndarray.tolist()
                training_bias20_list = training_bias20_ndarray.tolist()
                training_bias60_list = training_bias60_ndarray.tolist()
                training_bias120_list = training_bias120_ndarray.tolist()
                training_bias250_list = training_bias250_ndarray.tolist()
                training_ema12_list = training_ema12_ndarray.tolist()
                training_ema26_list = training_ema26_ndarray.tolist()
                training_dif_list = training_dif_ndarray.tolist()
                training_dea_list = training_dea_ndarray.tolist()
                training_rsv_list = training_rsv_ndarray.tolist()
                training_k_list = training_k_ndarray.tolist()
                training_d_list = training_d_ndarray.tolist()

                # 合并成训练数据
                X = np.column_stack(
                    [training_open_price_ndarray, training_close_price_ndarray, training_highest_price_ndarray,
                     training_lowest_price_ndarray, training_change_amount_ndarray, training_change_range_ndarray,
                     training_volume_ndarray, training_turnover_ndarray,
                     training_ma5_ndarray, training_ma10_ndarray, training_ma20_ndarray, training_ma60_ndarray,
                     training_ma120_ndarray, training_ma250_ndarray,
                     training_ha_open_price_ndarray, training_ha_close_price_ndarray,
                     training_ha_highest_price_ndarray,
                     training_ha_lowest_price_ndarray, training_bias5_ndarray, training_bias10_ndarray,
                     training_bias20_ndarray, training_bias60_ndarray, training_bias120_ndarray,
                     training_bias250_ndarray, training_ema12_ndarray, training_ema26_ndarray, training_dif_ndarray,
                     training_dea_ndarray, training_rsv_ndarray, training_k_ndarray, training_d_ndarray])

                # print(np.sum(X, axis=1))
                # 将数据送入模型，进行隐马尔科夫预测
                model = GaussianHMM(n_components=HmmConfig.Status_Number, covariance_type="full", n_iter=2000).fit(
                    X)
                transmat_init = np.ones(
                    (HmmConfig.Status_Number, HmmConfig.Status_Number)) / HmmConfig.Status_Number
                model.transmat_ = transmat_init
                # print(model.means_)
                # print(DatetimeUtil.datetime_to_str(training_end_date, DatetimeFormat.Date_Format_With_Line))
                # if DatetimeUtil.datetime_to_str(training_end_date, DatetimeFormat.Date_Format_With_Line) == "2014-05-01":
                #     print(np.sum(training_one_day_log_turnover_difference_ndarray))
                #     print(np.sum(training_five_day_log_turnover_difference_ndarray))
                #     print(np.sum(training_one_day_log_close_price_difference_ndarray))
                #     print(np.sum(training_five_day_log_close_price_difference_difference_ndarray))
                #     print(np.sum(training_five_day_log_highest_price_lowest_price_difference_ndarray))
                # print(training_one_day_log_turnover_difference_ndarray[len(training_one_day_log_turnover_difference_ndarray) - 1])
                # print(np.sum(model.transmat_))
                hidden_state_ndarray = model.predict(X)

                # 打印包含状态的折线图
                if HmmConfig.Save_Line_Picture:
                    training_date_dataframe = pd.DataFrame(training_date_list)
                    training_close_price_dataframe = pd.DataFrame(training_close_price_list)
                    plt.figure(figsize=(25, 18))
                    for i in range(model.n_components):
                        pos = (hidden_state_ndarray == i)
                        plt.plot_date(training_date_dataframe[pos], training_close_price_dataframe[pos],
                                      'o',
                                      label='hidden state %d' % i, lw=2)
                        plt.legend()
                    # plt.show()
                    fig = plt.gcf()  # 获取当前figure
                    plt.close(fig)  # 关闭传入的 figure 对象

                # 每一种状态都测试一遍：当前交易日开仓，第二天如果状态相同测持有，否则平仓
                training_result_ndarray = np.zeros((HmmConfig.Status_Number, 2))
                for training_status in range(0, HmmConfig.Status_Number):
                    Logger.info("当前测试的状态为[%d]", training_status)

                    # 当前收益率，初始化为100%
                    training_current_profit: float = 100.00
                    # 是否持仓
                    training_holding: bool = False
                    # 买入价
                    training_buying_price: float
                    # 记录所有状态收益率的二维数组
                    training_profit_ndarray = np.zeros(
                        (HmmConfig.Status_Number, len(training_date_list) + 1))
                    # 初始化记录所有状态收益率的二维数组
                    training_profit_ndarray[:, 0].fill(training_current_profit)

                    for index, hidden_state in enumerate(hidden_state_ndarray):
                        # 开仓
                        if training_holding is False and training_status == hidden_state:
                            training_buying_price = float(training_close_price_list[index])
                            training_holding = True
                        # 平仓
                        if training_holding is True and training_status != hidden_state:
                            if float(training_close_price_list[index]) - training_buying_price != 0:
                                training_current_profit = training_current_profit * (
                                        1 + (float(
                                    training_close_price_list[
                                        index]) - training_buying_price) / training_buying_price)
                            training_profit_ndarray[
                                HmmConfig.Status_Number - 1, index + 1] = training_current_profit
                            training_holding = False
                        # 空仓或持仓状态时
                        training_profit_ndarray[HmmConfig.Status_Number - 1, index] = training_current_profit

                    Logger.info("状态为[%d]，最后的收益率为[%f]", training_status, training_current_profit)
                    training_result_ndarray[training_status, 0] = training_status
                    training_result_ndarray[training_status, 1] = training_current_profit

                # 确定哪个状态做多，哪个状态做空
                # 做多的状态
                do_long_status: int
                # 做空的状态
                do_short_status: int
                # 初始化最大值
                max_profit: float = sys.float_info.min
                # 初始化最小值
                min_profit: float = sys.float_info.max
                for training_result in training_result_ndarray:
                    if training_result[1] > max_profit:
                        do_long_status = training_result[0]
                        max_profit = training_result[1]
                for training_result in training_result_ndarray:
                    if training_result[1] < min_profit:
                        do_short_status = training_result[0]
                        min_profit = training_result[1]
                Logger.info("状态为[%d]时做多，状态为[%d]时做空", do_long_status, do_short_status)

                # 用训练数据模拟真实交易
                if hidden_state_ndarray[len(hidden_state_ndarray) - 1] == do_long_status:
                    Logger.info("当前的状态是[" + str(do_long_status) + "]，因此属于多头态势")

                    if testing_holding_long is False:
                        # 如果没有持有多单，则开仓多单
                        Logger.info("当前没有持有多单，所以开仓多单")

                        testing_open_buying_price = original_training_close_price_list[
                            len(training_close_price_list) - 1]
                        testing_open_buying_date = training_date_list[
                            len(training_date_list) - 1]

                        testing_profit_ndarray[HmmConfig.Status_Number - 1][
                            testing_index] = testing_last_profit_and_loss_rate

                        testing_holding_long = True

                        # 开仓多单
                        model_hmm = ModelHmm()
                        model_hmm.code = etf_transaction_data.code_
                        model_hmm.buy_date = testing_open_buying_date
                        model_hmm.buy_price = testing_open_buying_price
                        model_hmm.direction = Direction.Up
                        self.model_hmm_dao.save(model_hmm)
                    else:
                        # 如果已经持有多单，则继续持有多单
                        Logger.info("当前已经持有多单，所以继续持有多单")

                        testing_profit_ndarray[HmmConfig.Status_Number - 1][
                            testing_index] = testing_last_profit_and_loss_rate

                elif hidden_state_ndarray[len(hidden_state_ndarray) - 1] == do_short_status:
                    Logger.info("当前的状态是[" + str(do_short_status) + "]，因此空头态势")

                    if testing_holding_long is True:
                        # 如果持有多单，则平仓多单
                        Logger.info("当前持有多单，所以平仓多单")

                        testing_close_buying_price = original_training_close_price_list[
                            len(training_close_price_list) - 1]
                        testing_close_buying_date = training_date_list[
                            len(training_date_list) - 1]

                        testing_current_profit = testing_current_profit * (
                                1 + (
                                float(testing_close_buying_price) - float(testing_open_buying_price)) / float(
                            testing_open_buying_price))
                        testing_profit_ndarray[HmmConfig.Status_Number - 1][testing_index] = testing_current_profit
                        testing_last_profit_and_loss_rate = testing_current_profit

                        testing_holding_long = False

                        # 平仓多单
                        query_kwargs = {
                            "code": etf_transaction_data.code_,
                            "buy_date": testing_open_buying_date
                        }
                        new_attrs_kwargs = {
                            "sell_date": testing_close_buying_date,
                            "sell_price": testing_close_buying_price,
                            "profit_loss": testing_close_buying_price - testing_open_buying_price,
                            "accumulative_profit_loss": testing_current_profit
                        }
                        self.model_hmm_dao.update_batch_by_query(query_kwargs, dict(),
                                                                 new_attrs_kwargs)

                        testing_profit_ndarray[HmmConfig.Status_Number - 1][
                            testing_index] = testing_last_profit_and_loss_rate

                else:
                    Logger.info(
                        "当前的状态是[" + str(
                            hidden_state_ndarray[len(hidden_state_ndarray) - 1]) + "]，不做任何操作")
                    if testing_holding_long is True:
                        Logger.info("之前的多单继续持有")

                    testing_profit_ndarray[
                        HmmConfig.Status_Number - 1, testing_index] = testing_last_profit_and_loss_rate

                Logger.info("当前的日期为[" + DatetimeUtil.datetime_to_str(training_date_list[
                                                                               len(training_date_list) - 1],
                                                                           DatetimeFormat.Date_Format_With_Line) + "]，当前的收益率：" +
                            testing_profit_ndarray[HmmConfig.Status_Number - 1][testing_index].astype(str))

                testing_index = testing_index + 1

            Logger.info("ETF[" + etf_transaction_data.code_ + "]经过测试之后的收益率为[" +
                        testing_profit_ndarray[HmmConfig.Status_Number - 1][testing_index].astype(str) + "]")

            # except Exception as e:
            #     Logger.error("在ETF[" + etf_transaction_data.code_ + "]上使用hmm算法时，报错[" + str(e) + "]")
            #     continue

    def create_hmm_profit_loss_and_close_price_line_picture(self):
        """
        创建hmm算法的收益和收盘价折线图
        """

        Logger.info("开始创建hmm算法的收益和收盘价折线图")

        plt.title('hmm算法的收益和收盘价折线图')
        plt.rcParams['font.sans-serif'] = ['SimHei']  # 显示汉字
        plt.xlabel('时间')
        plt.ylabel('收益率/收盘价')

        # 查询所有期货信息
        commodity_future_info_list = self.commodity_future_info_dao.find_all()
        if commodity_future_info_list is not None and len(commodity_future_info_list) > 0:
            for commodity_future_info in commodity_future_info_list:

                # 日期
                transaction_date_list = list()
                # hmm算法收益率
                accumulative_profit_loss_rate_list = list()
                # 收盘价
                close_price_list = list()

                # 查询某个期货，使用hmm算法的收益
                filter_dict = {'code': commodity_future_info.code}
                order_by_list = ['sell_date']
                model_hmm_list = self.model_hmm_dao.find_list(filter_dict, dict(), order_by_list)

                if model_hmm_list is None or len(model_hmm_list) == 0:
                    Logger.info("期货[" + commodity_future_info.code + "]没有hmm算法的交易记录")
                    continue

                # 查询某个期货，每日的交易记录
                filter_dict = {'code': commodity_future_info.code}
                order_by_list = ['transaction_date']
                commodity_future_date_data_list = self.commodity_future_date_data_dao.find_list(filter_dict, dict(),
                                                                                                order_by_list)

                # 处理日期、收盘价
                for commodity_future_date_data in commodity_future_date_data_list:
                    transaction_date_list.append(commodity_future_date_data.transaction_date)
                    close_price_list.append(commodity_future_date_data.close_price)
                # 处理收益率
                last_accumulative_profit_and_loss_rate = Decimal(100.00)
                match = False
                for commodity_future_date_data in commodity_future_date_data_list:
                    match = False
                    for model_hmm in model_hmm_list:
                        if model_hmm.direction == Direction.Up and commodity_future_date_data.transaction_date == model_hmm.sell_date:
                            accumulative_profit_loss_rate_list.append(model_hmm.accumulative_profit_loss)
                            last_accumulative_profit_and_loss_rate = model_hmm.accumulative_profit_loss
                            match = True
                        if model_hmm.direction == Direction.Down and commodity_future_date_data.transaction_date == model_hmm.buy_date:
                            accumulative_profit_loss_rate_list.append(model_hmm.accumulative_profit_loss)
                            last_accumulative_profit_and_loss_rate = model_hmm.accumulative_profit_loss
                            match = True
                    if not match:
                        accumulative_profit_loss_rate_list.append(last_accumulative_profit_and_loss_rate)

                close_price_list = MathUtil.normalize(close_price_list)[0]
                accumulative_profit_loss_rate_list = MathUtil.normalize(accumulative_profit_loss_rate_list)[0]
                plt.plot(transaction_date_list, close_price_list, label='收盘价', marker='o', markersize=3)
                plt.plot(transaction_date_list, accumulative_profit_loss_rate_list, label='收益率', marker='*',
                         markersize=3)

                # 保存图表
                plt.savefig(HmmConfig.Save_Profit_Loss_Rate_And_Close_Price_Path + commodity_future_info.code + ".png")
                # 关闭图表
                plt.close()

    def analysis_hmm_result(self):
        """
        分析hmm算法的结果
        """

        Logger.info("开始分析hmm算法的结果")

        # 查询所有期货信息
        commodity_future_info_list = self.commodity_future_info_dao.find_all()
        if commodity_future_info_list is not None and len(commodity_future_info_list) > 0:

            total_accumulative_profit_loss_rate = Decimal()
            average_profit_loss_rate = Decimal()
            num: int = 0

            for commodity_future_info in commodity_future_info_list:
                # 查询某个期货，使用hmm算法的收益
                filter_dict = {'code': commodity_future_info.code}
                order_by_list = ['-sell_date']
                model_hmm_list = self.model_hmm_dao.find_list(filter_dict, dict(), order_by_list)

                if model_hmm_list is not None and len(model_hmm_list) != 0:
                    accumulative_profit_loss = model_hmm_list[0].accumulative_profit_loss if model_hmm_list[0].accumulative_profit_loss is not None else model_hmm_list[1].accumulative_profit_loss
                    num = num + 1
                    Logger.info("期货[%s]的最后收益率是[%f]", commodity_future_info.code, accumulative_profit_loss)

                    total_accumulative_profit_loss_rate = total_accumulative_profit_loss_rate + accumulative_profit_loss

            average_profit_loss_rate = total_accumulative_profit_loss_rate / Decimal(num)
            Logger.info("所有期货最后的平均收益率是[%f]", average_profit_loss_rate)
